net/mlx5: fix invalid flow item 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                         ret = -ENOTSUP;
831                         goto exit_item_not_supported;
832                 }
833                 cur_item = token;
834                 ret = mlx5_flow_item_validate(items,
835                                               (const uint8_t *)cur_item->mask,
836                                               cur_item->mask_sz);
837                 if (ret)
838                         goto exit_item_not_supported;
839                 if (items->type == RTE_FLOW_ITEM_TYPE_VXLAN) {
840                         if (parser->inner) {
841                                 rte_flow_error_set(error, ENOTSUP,
842                                                    RTE_FLOW_ERROR_TYPE_ITEM,
843                                                    items,
844                                                    "cannot recognize multiple"
845                                                    " VXLAN encapsulations");
846                                 return -rte_errno;
847                         }
848                         parser->inner = IBV_FLOW_SPEC_INNER;
849                 }
850                 if (parser->drop) {
851                         parser->queue[HASH_RXQ_ETH].offset += cur_item->dst_sz;
852                 } else {
853                         for (n = 0; n != hash_rxq_init_n; ++n)
854                                 parser->queue[n].offset += cur_item->dst_sz;
855                 }
856         }
857         if (parser->drop) {
858                 parser->queue[HASH_RXQ_ETH].offset +=
859                         sizeof(struct ibv_flow_spec_action_drop);
860         }
861         if (parser->mark) {
862                 for (i = 0; i != hash_rxq_init_n; ++i)
863                         parser->queue[i].offset +=
864                                 sizeof(struct ibv_flow_spec_action_tag);
865         }
866         if (parser->count) {
867                 unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
868
869                 for (i = 0; i != hash_rxq_init_n; ++i)
870                         parser->queue[i].offset += size;
871         }
872         return 0;
873 exit_item_not_supported:
874         return rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_ITEM,
875                                   items, "item not supported");
876 }
877
878 /**
879  * Allocate memory space to store verbs flow attributes.
880  *
881  * @param[in] size
882  *   Amount of byte to allocate.
883  * @param[out] error
884  *   Perform verbose error reporting if not NULL.
885  *
886  * @return
887  *   A verbs flow attribute on success, NULL otherwise and rte_errno is set.
888  */
889 static struct ibv_flow_attr *
890 mlx5_flow_convert_allocate(unsigned int size, struct rte_flow_error *error)
891 {
892         struct ibv_flow_attr *ibv_attr;
893
894         ibv_attr = rte_calloc(__func__, 1, size, 0);
895         if (!ibv_attr) {
896                 rte_flow_error_set(error, ENOMEM,
897                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
898                                    NULL,
899                                    "cannot allocate verbs spec attributes");
900                 return NULL;
901         }
902         return ibv_attr;
903 }
904
905 /**
906  * Make inner packet matching with an higher priority from the non Inner
907  * matching.
908  *
909  * @param[in, out] parser
910  *   Internal parser structure.
911  * @param attr
912  *   User flow attribute.
913  */
914 static void
915 mlx5_flow_update_priority(struct mlx5_flow_parse *parser,
916                           const struct rte_flow_attr *attr)
917 {
918         unsigned int i;
919
920         if (parser->drop) {
921                 parser->queue[HASH_RXQ_ETH].ibv_attr->priority =
922                         attr->priority +
923                         hash_rxq_init[HASH_RXQ_ETH].flow_priority;
924                 return;
925         }
926         for (i = 0; i != hash_rxq_init_n; ++i) {
927                 if (parser->queue[i].ibv_attr) {
928                         parser->queue[i].ibv_attr->priority =
929                                 attr->priority +
930                                 hash_rxq_init[i].flow_priority -
931                                 (parser->inner ? 1 : 0);
932                 }
933         }
934 }
935
936 /**
937  * Finalise verbs flow attributes.
938  *
939  * @param[in, out] parser
940  *   Internal parser structure.
941  */
942 static void
943 mlx5_flow_convert_finalise(struct mlx5_flow_parse *parser)
944 {
945         const unsigned int ipv4 =
946                 hash_rxq_init[parser->layer].ip_version == MLX5_IPV4;
947         const enum hash_rxq_type hmin = ipv4 ? HASH_RXQ_TCPV4 : HASH_RXQ_TCPV6;
948         const enum hash_rxq_type hmax = ipv4 ? HASH_RXQ_IPV4 : HASH_RXQ_IPV6;
949         const enum hash_rxq_type ohmin = ipv4 ? HASH_RXQ_TCPV6 : HASH_RXQ_TCPV4;
950         const enum hash_rxq_type ohmax = ipv4 ? HASH_RXQ_IPV6 : HASH_RXQ_IPV4;
951         const enum hash_rxq_type ip = ipv4 ? HASH_RXQ_IPV4 : HASH_RXQ_IPV6;
952         unsigned int i;
953
954         /* Remove any other flow not matching the pattern. */
955         if (parser->queues_n == 1 && !parser->rss_conf.rss_hf) {
956                 for (i = 0; i != hash_rxq_init_n; ++i) {
957                         if (i == HASH_RXQ_ETH)
958                                 continue;
959                         rte_free(parser->queue[i].ibv_attr);
960                         parser->queue[i].ibv_attr = NULL;
961                 }
962                 return;
963         }
964         if (parser->layer == HASH_RXQ_ETH) {
965                 goto fill;
966         } else {
967                 /*
968                  * This layer becomes useless as the pattern define under
969                  * layers.
970                  */
971                 rte_free(parser->queue[HASH_RXQ_ETH].ibv_attr);
972                 parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
973         }
974         /* Remove opposite kind of layer e.g. IPv6 if the pattern is IPv4. */
975         for (i = ohmin; i != (ohmax + 1); ++i) {
976                 if (!parser->queue[i].ibv_attr)
977                         continue;
978                 rte_free(parser->queue[i].ibv_attr);
979                 parser->queue[i].ibv_attr = NULL;
980         }
981         /* Remove impossible flow according to the RSS configuration. */
982         if (hash_rxq_init[parser->layer].dpdk_rss_hf &
983             parser->rss_conf.rss_hf) {
984                 /* Remove any other flow. */
985                 for (i = hmin; i != (hmax + 1); ++i) {
986                         if ((i == parser->layer) ||
987                              (!parser->queue[i].ibv_attr))
988                                 continue;
989                         rte_free(parser->queue[i].ibv_attr);
990                         parser->queue[i].ibv_attr = NULL;
991                 }
992         } else  if (!parser->queue[ip].ibv_attr) {
993                 /* no RSS possible with the current configuration. */
994                 parser->queues_n = 1;
995                 return;
996         }
997 fill:
998         /*
999          * Fill missing layers in verbs specifications, or compute the correct
1000          * offset to allocate the memory space for the attributes and
1001          * specifications.
1002          */
1003         for (i = 0; i != hash_rxq_init_n - 1; ++i) {
1004                 union {
1005                         struct ibv_flow_spec_ipv4_ext ipv4;
1006                         struct ibv_flow_spec_ipv6 ipv6;
1007                         struct ibv_flow_spec_tcp_udp udp_tcp;
1008                 } specs;
1009                 void *dst;
1010                 uint16_t size;
1011
1012                 if (i == parser->layer)
1013                         continue;
1014                 if (parser->layer == HASH_RXQ_ETH) {
1015                         if (hash_rxq_init[i].ip_version == MLX5_IPV4) {
1016                                 size = sizeof(struct ibv_flow_spec_ipv4_ext);
1017                                 specs.ipv4 = (struct ibv_flow_spec_ipv4_ext){
1018                                         .type = IBV_FLOW_SPEC_IPV4_EXT,
1019                                         .size = size,
1020                                 };
1021                         } else {
1022                                 size = sizeof(struct ibv_flow_spec_ipv6);
1023                                 specs.ipv6 = (struct ibv_flow_spec_ipv6){
1024                                         .type = IBV_FLOW_SPEC_IPV6,
1025                                         .size = size,
1026                                 };
1027                         }
1028                         if (parser->queue[i].ibv_attr) {
1029                                 dst = (void *)((uintptr_t)
1030                                                parser->queue[i].ibv_attr +
1031                                                parser->queue[i].offset);
1032                                 memcpy(dst, &specs, size);
1033                                 ++parser->queue[i].ibv_attr->num_of_specs;
1034                         }
1035                         parser->queue[i].offset += size;
1036                 }
1037                 if ((i == HASH_RXQ_UDPV4) || (i == HASH_RXQ_TCPV4) ||
1038                     (i == HASH_RXQ_UDPV6) || (i == HASH_RXQ_TCPV6)) {
1039                         size = sizeof(struct ibv_flow_spec_tcp_udp);
1040                         specs.udp_tcp = (struct ibv_flow_spec_tcp_udp) {
1041                                 .type = ((i == HASH_RXQ_UDPV4 ||
1042                                           i == HASH_RXQ_UDPV6) ?
1043                                          IBV_FLOW_SPEC_UDP :
1044                                          IBV_FLOW_SPEC_TCP),
1045                                 .size = size,
1046                         };
1047                         if (parser->queue[i].ibv_attr) {
1048                                 dst = (void *)((uintptr_t)
1049                                                parser->queue[i].ibv_attr +
1050                                                parser->queue[i].offset);
1051                                 memcpy(dst, &specs, size);
1052                                 ++parser->queue[i].ibv_attr->num_of_specs;
1053                         }
1054                         parser->queue[i].offset += size;
1055                 }
1056         }
1057 }
1058
1059 /**
1060  * Validate and convert a flow supported by the NIC.
1061  *
1062  * @param dev
1063  *   Pointer to Ethernet device.
1064  * @param[in] attr
1065  *   Flow rule attributes.
1066  * @param[in] pattern
1067  *   Pattern specification (list terminated by the END pattern item).
1068  * @param[in] actions
1069  *   Associated actions (list terminated by the END action).
1070  * @param[out] error
1071  *   Perform verbose error reporting if not NULL.
1072  * @param[in, out] parser
1073  *   Internal parser structure.
1074  *
1075  * @return
1076  *   0 on success, a negative errno value otherwise and rte_errno is set.
1077  */
1078 static int
1079 mlx5_flow_convert(struct rte_eth_dev *dev,
1080                   const struct rte_flow_attr *attr,
1081                   const struct rte_flow_item items[],
1082                   const struct rte_flow_action actions[],
1083                   struct rte_flow_error *error,
1084                   struct mlx5_flow_parse *parser)
1085 {
1086         const struct mlx5_flow_items *cur_item = mlx5_flow_items;
1087         unsigned int i;
1088         int ret;
1089
1090         /* First step. Validate the attributes, items and actions. */
1091         *parser = (struct mlx5_flow_parse){
1092                 .create = parser->create,
1093                 .layer = HASH_RXQ_ETH,
1094                 .mark_id = MLX5_FLOW_MARK_DEFAULT,
1095         };
1096         ret = mlx5_flow_convert_attributes(attr, error);
1097         if (ret)
1098                 return ret;
1099         ret = mlx5_flow_convert_actions(dev, actions, error, parser);
1100         if (ret)
1101                 return ret;
1102         ret = mlx5_flow_convert_items_validate(items, error, parser);
1103         if (ret)
1104                 return ret;
1105         mlx5_flow_convert_finalise(parser);
1106         /*
1107          * Second step.
1108          * Allocate the memory space to store verbs specifications.
1109          */
1110         if (parser->drop) {
1111                 unsigned int offset = parser->queue[HASH_RXQ_ETH].offset;
1112
1113                 parser->queue[HASH_RXQ_ETH].ibv_attr =
1114                         mlx5_flow_convert_allocate(offset, error);
1115                 if (!parser->queue[HASH_RXQ_ETH].ibv_attr)
1116                         goto exit_enomem;
1117                 parser->queue[HASH_RXQ_ETH].offset =
1118                         sizeof(struct ibv_flow_attr);
1119         } else {
1120                 for (i = 0; i != hash_rxq_init_n; ++i) {
1121                         unsigned int offset;
1122
1123                         if (!(parser->rss_conf.rss_hf &
1124                               hash_rxq_init[i].dpdk_rss_hf) &&
1125                             (i != HASH_RXQ_ETH))
1126                                 continue;
1127                         offset = parser->queue[i].offset;
1128                         parser->queue[i].ibv_attr =
1129                                 mlx5_flow_convert_allocate(offset, error);
1130                         if (!parser->queue[i].ibv_attr)
1131                                 goto exit_enomem;
1132                         parser->queue[i].offset = sizeof(struct ibv_flow_attr);
1133                 }
1134         }
1135         /* Third step. Conversion parse, fill the specifications. */
1136         parser->inner = 0;
1137         for (; items->type != RTE_FLOW_ITEM_TYPE_END; ++items) {
1138                 struct mlx5_flow_data data = {
1139                         .parser = parser,
1140                         .error = error,
1141                 };
1142
1143                 if (items->type == RTE_FLOW_ITEM_TYPE_VOID)
1144                         continue;
1145                 cur_item = &mlx5_flow_items[items->type];
1146                 ret = cur_item->convert(items,
1147                                         (cur_item->default_mask ?
1148                                          cur_item->default_mask :
1149                                          cur_item->mask),
1150                                          &data);
1151                 if (ret)
1152                         goto exit_free;
1153         }
1154         if (parser->mark)
1155                 mlx5_flow_create_flag_mark(parser, parser->mark_id);
1156         if (parser->count && parser->create) {
1157                 mlx5_flow_create_count(dev, parser);
1158                 if (!parser->cs)
1159                         goto exit_count_error;
1160         }
1161         /*
1162          * Last step. Complete missing specification to reach the RSS
1163          * configuration.
1164          */
1165         if (!parser->drop)
1166                 mlx5_flow_convert_finalise(parser);
1167         mlx5_flow_update_priority(parser, attr);
1168 exit_free:
1169         /* Only verification is expected, all resources should be released. */
1170         if (!parser->create) {
1171                 for (i = 0; i != hash_rxq_init_n; ++i) {
1172                         if (parser->queue[i].ibv_attr) {
1173                                 rte_free(parser->queue[i].ibv_attr);
1174                                 parser->queue[i].ibv_attr = NULL;
1175                         }
1176                 }
1177         }
1178         return ret;
1179 exit_enomem:
1180         for (i = 0; i != hash_rxq_init_n; ++i) {
1181                 if (parser->queue[i].ibv_attr) {
1182                         rte_free(parser->queue[i].ibv_attr);
1183                         parser->queue[i].ibv_attr = NULL;
1184                 }
1185         }
1186         rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1187                            NULL, "cannot allocate verbs spec attributes");
1188         return -rte_errno;
1189 exit_count_error:
1190         rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1191                            NULL, "cannot create counter");
1192         return -rte_errno;
1193 }
1194
1195 /**
1196  * Copy the specification created into the flow.
1197  *
1198  * @param parser
1199  *   Internal parser structure.
1200  * @param src
1201  *   Create specification.
1202  * @param size
1203  *   Size in bytes of the specification to copy.
1204  */
1205 static void
1206 mlx5_flow_create_copy(struct mlx5_flow_parse *parser, void *src,
1207                       unsigned int size)
1208 {
1209         unsigned int i;
1210         void *dst;
1211
1212         for (i = 0; i != hash_rxq_init_n; ++i) {
1213                 if (!parser->queue[i].ibv_attr)
1214                         continue;
1215                 /* Specification must be the same l3 type or none. */
1216                 if (parser->layer == HASH_RXQ_ETH ||
1217                     (hash_rxq_init[parser->layer].ip_version ==
1218                      hash_rxq_init[i].ip_version) ||
1219                     (hash_rxq_init[i].ip_version == 0)) {
1220                         dst = (void *)((uintptr_t)parser->queue[i].ibv_attr +
1221                                         parser->queue[i].offset);
1222                         memcpy(dst, src, size);
1223                         ++parser->queue[i].ibv_attr->num_of_specs;
1224                         parser->queue[i].offset += size;
1225                 }
1226         }
1227 }
1228
1229 /**
1230  * Convert Ethernet item to Verbs specification.
1231  *
1232  * @param item[in]
1233  *   Item specification.
1234  * @param default_mask[in]
1235  *   Default bit-masks to use when item->mask is not provided.
1236  * @param data[in, out]
1237  *   User structure.
1238  *
1239  * @return
1240  *   0 on success, a negative errno value otherwise and rte_errno is set.
1241  */
1242 static int
1243 mlx5_flow_create_eth(const struct rte_flow_item *item,
1244                      const void *default_mask,
1245                      struct mlx5_flow_data *data)
1246 {
1247         const struct rte_flow_item_eth *spec = item->spec;
1248         const struct rte_flow_item_eth *mask = item->mask;
1249         struct mlx5_flow_parse *parser = data->parser;
1250         const unsigned int eth_size = sizeof(struct ibv_flow_spec_eth);
1251         struct ibv_flow_spec_eth eth = {
1252                 .type = parser->inner | IBV_FLOW_SPEC_ETH,
1253                 .size = eth_size,
1254         };
1255
1256         /* Don't update layer for the inner pattern. */
1257         if (!parser->inner)
1258                 parser->layer = HASH_RXQ_ETH;
1259         if (spec) {
1260                 unsigned int i;
1261
1262                 if (!mask)
1263                         mask = default_mask;
1264                 memcpy(&eth.val.dst_mac, spec->dst.addr_bytes, ETHER_ADDR_LEN);
1265                 memcpy(&eth.val.src_mac, spec->src.addr_bytes, ETHER_ADDR_LEN);
1266                 eth.val.ether_type = spec->type;
1267                 memcpy(&eth.mask.dst_mac, mask->dst.addr_bytes, ETHER_ADDR_LEN);
1268                 memcpy(&eth.mask.src_mac, mask->src.addr_bytes, ETHER_ADDR_LEN);
1269                 eth.mask.ether_type = mask->type;
1270                 /* Remove unwanted bits from values. */
1271                 for (i = 0; i < ETHER_ADDR_LEN; ++i) {
1272                         eth.val.dst_mac[i] &= eth.mask.dst_mac[i];
1273                         eth.val.src_mac[i] &= eth.mask.src_mac[i];
1274                 }
1275                 eth.val.ether_type &= eth.mask.ether_type;
1276         }
1277         mlx5_flow_create_copy(parser, &eth, eth_size);
1278         return 0;
1279 }
1280
1281 /**
1282  * Convert VLAN item to Verbs specification.
1283  *
1284  * @param item[in]
1285  *   Item specification.
1286  * @param default_mask[in]
1287  *   Default bit-masks to use when item->mask is not provided.
1288  * @param data[in, out]
1289  *   User structure.
1290  *
1291  * @return
1292  *   0 on success, a negative errno value otherwise and rte_errno is set.
1293  */
1294 static int
1295 mlx5_flow_create_vlan(const struct rte_flow_item *item,
1296                       const void *default_mask,
1297                       struct mlx5_flow_data *data)
1298 {
1299         const struct rte_flow_item_vlan *spec = item->spec;
1300         const struct rte_flow_item_vlan *mask = item->mask;
1301         struct mlx5_flow_parse *parser = data->parser;
1302         struct ibv_flow_spec_eth *eth;
1303         const unsigned int eth_size = sizeof(struct ibv_flow_spec_eth);
1304
1305         if (spec) {
1306                 unsigned int i;
1307                 if (!mask)
1308                         mask = default_mask;
1309
1310                 for (i = 0; i != hash_rxq_init_n; ++i) {
1311                         if (!parser->queue[i].ibv_attr)
1312                                 continue;
1313
1314                         eth = (void *)((uintptr_t)parser->queue[i].ibv_attr +
1315                                        parser->queue[i].offset - eth_size);
1316                         eth->val.vlan_tag = spec->tci;
1317                         eth->mask.vlan_tag = mask->tci;
1318                         eth->val.vlan_tag &= eth->mask.vlan_tag;
1319                         /*
1320                          * From verbs perspective an empty VLAN is equivalent
1321                          * to a packet without VLAN layer.
1322                          */
1323                         if (!eth->mask.vlan_tag)
1324                                 goto error;
1325                 }
1326                 return 0;
1327         }
1328 error:
1329         return rte_flow_error_set(data->error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
1330                                   item, "VLAN cannot be empty");
1331 }
1332
1333 /**
1334  * Convert IPv4 item to Verbs specification.
1335  *
1336  * @param item[in]
1337  *   Item specification.
1338  * @param default_mask[in]
1339  *   Default bit-masks to use when item->mask is not provided.
1340  * @param data[in, out]
1341  *   User structure.
1342  *
1343  * @return
1344  *   0 on success, a negative errno value otherwise and rte_errno is set.
1345  */
1346 static int
1347 mlx5_flow_create_ipv4(const struct rte_flow_item *item,
1348                       const void *default_mask,
1349                       struct mlx5_flow_data *data)
1350 {
1351         const struct rte_flow_item_ipv4 *spec = item->spec;
1352         const struct rte_flow_item_ipv4 *mask = item->mask;
1353         struct mlx5_flow_parse *parser = data->parser;
1354         unsigned int ipv4_size = sizeof(struct ibv_flow_spec_ipv4_ext);
1355         struct ibv_flow_spec_ipv4_ext ipv4 = {
1356                 .type = parser->inner | IBV_FLOW_SPEC_IPV4_EXT,
1357                 .size = ipv4_size,
1358         };
1359
1360         /* Don't update layer for the inner pattern. */
1361         if (!parser->inner)
1362                 parser->layer = HASH_RXQ_IPV4;
1363         if (spec) {
1364                 if (!mask)
1365                         mask = default_mask;
1366                 ipv4.val = (struct ibv_flow_ipv4_ext_filter){
1367                         .src_ip = spec->hdr.src_addr,
1368                         .dst_ip = spec->hdr.dst_addr,
1369                         .proto = spec->hdr.next_proto_id,
1370                         .tos = spec->hdr.type_of_service,
1371                 };
1372                 ipv4.mask = (struct ibv_flow_ipv4_ext_filter){
1373                         .src_ip = mask->hdr.src_addr,
1374                         .dst_ip = mask->hdr.dst_addr,
1375                         .proto = mask->hdr.next_proto_id,
1376                         .tos = mask->hdr.type_of_service,
1377                 };
1378                 /* Remove unwanted bits from values. */
1379                 ipv4.val.src_ip &= ipv4.mask.src_ip;
1380                 ipv4.val.dst_ip &= ipv4.mask.dst_ip;
1381                 ipv4.val.proto &= ipv4.mask.proto;
1382                 ipv4.val.tos &= ipv4.mask.tos;
1383         }
1384         mlx5_flow_create_copy(parser, &ipv4, ipv4_size);
1385         return 0;
1386 }
1387
1388 /**
1389  * Convert IPv6 item to Verbs specification.
1390  *
1391  * @param item[in]
1392  *   Item specification.
1393  * @param default_mask[in]
1394  *   Default bit-masks to use when item->mask is not provided.
1395  * @param data[in, out]
1396  *   User structure.
1397  *
1398  * @return
1399  *   0 on success, a negative errno value otherwise and rte_errno is set.
1400  */
1401 static int
1402 mlx5_flow_create_ipv6(const struct rte_flow_item *item,
1403                       const void *default_mask,
1404                       struct mlx5_flow_data *data)
1405 {
1406         const struct rte_flow_item_ipv6 *spec = item->spec;
1407         const struct rte_flow_item_ipv6 *mask = item->mask;
1408         struct mlx5_flow_parse *parser = data->parser;
1409         unsigned int ipv6_size = sizeof(struct ibv_flow_spec_ipv6);
1410         struct ibv_flow_spec_ipv6 ipv6 = {
1411                 .type = parser->inner | IBV_FLOW_SPEC_IPV6,
1412                 .size = ipv6_size,
1413         };
1414
1415         /* Don't update layer for the inner pattern. */
1416         if (!parser->inner)
1417                 parser->layer = HASH_RXQ_IPV6;
1418         if (spec) {
1419                 unsigned int i;
1420                 uint32_t vtc_flow_val;
1421                 uint32_t vtc_flow_mask;
1422
1423                 if (!mask)
1424                         mask = default_mask;
1425                 memcpy(&ipv6.val.src_ip, spec->hdr.src_addr,
1426                        RTE_DIM(ipv6.val.src_ip));
1427                 memcpy(&ipv6.val.dst_ip, spec->hdr.dst_addr,
1428                        RTE_DIM(ipv6.val.dst_ip));
1429                 memcpy(&ipv6.mask.src_ip, mask->hdr.src_addr,
1430                        RTE_DIM(ipv6.mask.src_ip));
1431                 memcpy(&ipv6.mask.dst_ip, mask->hdr.dst_addr,
1432                        RTE_DIM(ipv6.mask.dst_ip));
1433                 vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);
1434                 vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);
1435                 ipv6.val.flow_label =
1436                         rte_cpu_to_be_32((vtc_flow_val & IPV6_HDR_FL_MASK) >>
1437                                          IPV6_HDR_FL_SHIFT);
1438                 ipv6.val.traffic_class = (vtc_flow_val & IPV6_HDR_TC_MASK) >>
1439                                          IPV6_HDR_TC_SHIFT;
1440                 ipv6.val.next_hdr = spec->hdr.proto;
1441                 ipv6.val.hop_limit = spec->hdr.hop_limits;
1442                 ipv6.mask.flow_label =
1443                         rte_cpu_to_be_32((vtc_flow_mask & IPV6_HDR_FL_MASK) >>
1444                                          IPV6_HDR_FL_SHIFT);
1445                 ipv6.mask.traffic_class = (vtc_flow_mask & IPV6_HDR_TC_MASK) >>
1446                                           IPV6_HDR_TC_SHIFT;
1447                 ipv6.mask.next_hdr = mask->hdr.proto;
1448                 ipv6.mask.hop_limit = mask->hdr.hop_limits;
1449                 /* Remove unwanted bits from values. */
1450                 for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {
1451                         ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];
1452                         ipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];
1453                 }
1454                 ipv6.val.flow_label &= ipv6.mask.flow_label;
1455                 ipv6.val.traffic_class &= ipv6.mask.traffic_class;
1456                 ipv6.val.next_hdr &= ipv6.mask.next_hdr;
1457                 ipv6.val.hop_limit &= ipv6.mask.hop_limit;
1458         }
1459         mlx5_flow_create_copy(parser, &ipv6, ipv6_size);
1460         return 0;
1461 }
1462
1463 /**
1464  * Convert UDP item to Verbs specification.
1465  *
1466  * @param item[in]
1467  *   Item specification.
1468  * @param default_mask[in]
1469  *   Default bit-masks to use when item->mask is not provided.
1470  * @param data[in, out]
1471  *   User structure.
1472  *
1473  * @return
1474  *   0 on success, a negative errno value otherwise and rte_errno is set.
1475  */
1476 static int
1477 mlx5_flow_create_udp(const struct rte_flow_item *item,
1478                      const void *default_mask,
1479                      struct mlx5_flow_data *data)
1480 {
1481         const struct rte_flow_item_udp *spec = item->spec;
1482         const struct rte_flow_item_udp *mask = item->mask;
1483         struct mlx5_flow_parse *parser = data->parser;
1484         unsigned int udp_size = sizeof(struct ibv_flow_spec_tcp_udp);
1485         struct ibv_flow_spec_tcp_udp udp = {
1486                 .type = parser->inner | IBV_FLOW_SPEC_UDP,
1487                 .size = udp_size,
1488         };
1489
1490         /* Don't update layer for the inner pattern. */
1491         if (!parser->inner) {
1492                 if (parser->layer == HASH_RXQ_IPV4)
1493                         parser->layer = HASH_RXQ_UDPV4;
1494                 else
1495                         parser->layer = HASH_RXQ_UDPV6;
1496         }
1497         if (spec) {
1498                 if (!mask)
1499                         mask = default_mask;
1500                 udp.val.dst_port = spec->hdr.dst_port;
1501                 udp.val.src_port = spec->hdr.src_port;
1502                 udp.mask.dst_port = mask->hdr.dst_port;
1503                 udp.mask.src_port = mask->hdr.src_port;
1504                 /* Remove unwanted bits from values. */
1505                 udp.val.src_port &= udp.mask.src_port;
1506                 udp.val.dst_port &= udp.mask.dst_port;
1507         }
1508         mlx5_flow_create_copy(parser, &udp, udp_size);
1509         return 0;
1510 }
1511
1512 /**
1513  * Convert TCP item to Verbs specification.
1514  *
1515  * @param item[in]
1516  *   Item specification.
1517  * @param default_mask[in]
1518  *   Default bit-masks to use when item->mask is not provided.
1519  * @param data[in, out]
1520  *   User structure.
1521  *
1522  * @return
1523  *   0 on success, a negative errno value otherwise and rte_errno is set.
1524  */
1525 static int
1526 mlx5_flow_create_tcp(const struct rte_flow_item *item,
1527                      const void *default_mask,
1528                      struct mlx5_flow_data *data)
1529 {
1530         const struct rte_flow_item_tcp *spec = item->spec;
1531         const struct rte_flow_item_tcp *mask = item->mask;
1532         struct mlx5_flow_parse *parser = data->parser;
1533         unsigned int tcp_size = sizeof(struct ibv_flow_spec_tcp_udp);
1534         struct ibv_flow_spec_tcp_udp tcp = {
1535                 .type = parser->inner | IBV_FLOW_SPEC_TCP,
1536                 .size = tcp_size,
1537         };
1538
1539         /* Don't update layer for the inner pattern. */
1540         if (!parser->inner) {
1541                 if (parser->layer == HASH_RXQ_IPV4)
1542                         parser->layer = HASH_RXQ_TCPV4;
1543                 else
1544                         parser->layer = HASH_RXQ_TCPV6;
1545         }
1546         if (spec) {
1547                 if (!mask)
1548                         mask = default_mask;
1549                 tcp.val.dst_port = spec->hdr.dst_port;
1550                 tcp.val.src_port = spec->hdr.src_port;
1551                 tcp.mask.dst_port = mask->hdr.dst_port;
1552                 tcp.mask.src_port = mask->hdr.src_port;
1553                 /* Remove unwanted bits from values. */
1554                 tcp.val.src_port &= tcp.mask.src_port;
1555                 tcp.val.dst_port &= tcp.mask.dst_port;
1556         }
1557         mlx5_flow_create_copy(parser, &tcp, tcp_size);
1558         return 0;
1559 }
1560
1561 /**
1562  * Convert VXLAN item to Verbs specification.
1563  *
1564  * @param item[in]
1565  *   Item specification.
1566  * @param default_mask[in]
1567  *   Default bit-masks to use when item->mask is not provided.
1568  * @param data[in, out]
1569  *   User structure.
1570  *
1571  * @return
1572  *   0 on success, a negative errno value otherwise and rte_errno is set.
1573  */
1574 static int
1575 mlx5_flow_create_vxlan(const struct rte_flow_item *item,
1576                        const void *default_mask,
1577                        struct mlx5_flow_data *data)
1578 {
1579         const struct rte_flow_item_vxlan *spec = item->spec;
1580         const struct rte_flow_item_vxlan *mask = item->mask;
1581         struct mlx5_flow_parse *parser = data->parser;
1582         unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
1583         struct ibv_flow_spec_tunnel vxlan = {
1584                 .type = parser->inner | IBV_FLOW_SPEC_VXLAN_TUNNEL,
1585                 .size = size,
1586         };
1587         union vni {
1588                 uint32_t vlan_id;
1589                 uint8_t vni[4];
1590         } id;
1591
1592         id.vni[0] = 0;
1593         parser->inner = IBV_FLOW_SPEC_INNER;
1594         if (spec) {
1595                 if (!mask)
1596                         mask = default_mask;
1597                 memcpy(&id.vni[1], spec->vni, 3);
1598                 vxlan.val.tunnel_id = id.vlan_id;
1599                 memcpy(&id.vni[1], mask->vni, 3);
1600                 vxlan.mask.tunnel_id = id.vlan_id;
1601                 /* Remove unwanted bits from values. */
1602                 vxlan.val.tunnel_id &= vxlan.mask.tunnel_id;
1603         }
1604         /*
1605          * Tunnel id 0 is equivalent as not adding a VXLAN layer, if only this
1606          * layer is defined in the Verbs specification it is interpreted as
1607          * wildcard and all packets will match this rule, if it follows a full
1608          * stack layer (ex: eth / ipv4 / udp), all packets matching the layers
1609          * before will also match this rule.
1610          * To avoid such situation, VNI 0 is currently refused.
1611          */
1612         if (!vxlan.val.tunnel_id)
1613                 return rte_flow_error_set(data->error, EINVAL,
1614                                           RTE_FLOW_ERROR_TYPE_ITEM,
1615                                           item,
1616                                           "VxLAN vni cannot be 0");
1617         mlx5_flow_create_copy(parser, &vxlan, size);
1618         return 0;
1619 }
1620
1621 /**
1622  * Convert mark/flag action to Verbs specification.
1623  *
1624  * @param parser
1625  *   Internal parser structure.
1626  * @param mark_id
1627  *   Mark identifier.
1628  *
1629  * @return
1630  *   0 on success, a negative errno value otherwise and rte_errno is set.
1631  */
1632 static int
1633 mlx5_flow_create_flag_mark(struct mlx5_flow_parse *parser, uint32_t mark_id)
1634 {
1635         unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
1636         struct ibv_flow_spec_action_tag tag = {
1637                 .type = IBV_FLOW_SPEC_ACTION_TAG,
1638                 .size = size,
1639                 .tag_id = mlx5_flow_mark_set(mark_id),
1640         };
1641
1642         assert(parser->mark);
1643         mlx5_flow_create_copy(parser, &tag, size);
1644         return 0;
1645 }
1646
1647 /**
1648  * Convert count action to Verbs specification.
1649  *
1650  * @param dev
1651  *   Pointer to Ethernet device.
1652  * @param parser
1653  *   Pointer to MLX5 flow parser structure.
1654  *
1655  * @return
1656  *   0 on success, a negative errno value otherwise and rte_errno is set.
1657  */
1658 static int
1659 mlx5_flow_create_count(struct rte_eth_dev *dev __rte_unused,
1660                        struct mlx5_flow_parse *parser __rte_unused)
1661 {
1662 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
1663         struct priv *priv = dev->data->dev_private;
1664         unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
1665         struct ibv_counter_set_init_attr init_attr = {0};
1666         struct ibv_flow_spec_counter_action counter = {
1667                 .type = IBV_FLOW_SPEC_ACTION_COUNT,
1668                 .size = size,
1669                 .counter_set_handle = 0,
1670         };
1671
1672         init_attr.counter_set_id = 0;
1673         parser->cs = mlx5_glue->create_counter_set(priv->ctx, &init_attr);
1674         if (!parser->cs) {
1675                 rte_errno = EINVAL;
1676                 return -rte_errno;
1677         }
1678         counter.counter_set_handle = parser->cs->handle;
1679         mlx5_flow_create_copy(parser, &counter, size);
1680 #endif
1681         return 0;
1682 }
1683
1684 /**
1685  * Complete flow rule creation with a drop queue.
1686  *
1687  * @param dev
1688  *   Pointer to Ethernet device.
1689  * @param parser
1690  *   Internal parser structure.
1691  * @param flow
1692  *   Pointer to the rte_flow.
1693  * @param[out] error
1694  *   Perform verbose error reporting if not NULL.
1695  *
1696  * @return
1697  *   0 on success, a negative errno value otherwise and rte_errno is set.
1698  */
1699 static int
1700 mlx5_flow_create_action_queue_drop(struct rte_eth_dev *dev,
1701                                    struct mlx5_flow_parse *parser,
1702                                    struct rte_flow *flow,
1703                                    struct rte_flow_error *error)
1704 {
1705         struct priv *priv = dev->data->dev_private;
1706         struct ibv_flow_spec_action_drop *drop;
1707         unsigned int size = sizeof(struct ibv_flow_spec_action_drop);
1708
1709         assert(priv->pd);
1710         assert(priv->ctx);
1711         flow->drop = 1;
1712         drop = (void *)((uintptr_t)parser->queue[HASH_RXQ_ETH].ibv_attr +
1713                         parser->queue[HASH_RXQ_ETH].offset);
1714         *drop = (struct ibv_flow_spec_action_drop){
1715                         .type = IBV_FLOW_SPEC_ACTION_DROP,
1716                         .size = size,
1717         };
1718         ++parser->queue[HASH_RXQ_ETH].ibv_attr->num_of_specs;
1719         parser->queue[HASH_RXQ_ETH].offset += size;
1720         flow->frxq[HASH_RXQ_ETH].ibv_attr =
1721                 parser->queue[HASH_RXQ_ETH].ibv_attr;
1722         if (parser->count)
1723                 flow->cs = parser->cs;
1724         if (!priv->dev->data->dev_started)
1725                 return 0;
1726         parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
1727         flow->frxq[HASH_RXQ_ETH].ibv_flow =
1728                 mlx5_glue->create_flow(priv->flow_drop_queue->qp,
1729                                        flow->frxq[HASH_RXQ_ETH].ibv_attr);
1730         if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
1731                 rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1732                                    NULL, "flow rule creation failure");
1733                 goto error;
1734         }
1735         return 0;
1736 error:
1737         assert(flow);
1738         if (flow->frxq[HASH_RXQ_ETH].ibv_flow) {
1739                 claim_zero(mlx5_glue->destroy_flow
1740                            (flow->frxq[HASH_RXQ_ETH].ibv_flow));
1741                 flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
1742         }
1743         if (flow->frxq[HASH_RXQ_ETH].ibv_attr) {
1744                 rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
1745                 flow->frxq[HASH_RXQ_ETH].ibv_attr = NULL;
1746         }
1747         if (flow->cs) {
1748                 claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
1749                 flow->cs = NULL;
1750                 parser->cs = NULL;
1751         }
1752         return -rte_errno;
1753 }
1754
1755 /**
1756  * Create hash Rx queues when RSS is enabled.
1757  *
1758  * @param dev
1759  *   Pointer to Ethernet device.
1760  * @param parser
1761  *   Internal parser structure.
1762  * @param flow
1763  *   Pointer to the rte_flow.
1764  * @param[out] error
1765  *   Perform verbose error reporting if not NULL.
1766  *
1767  * @return
1768  *   0 on success, a negative errno value otherwise and rte_errno is set.
1769  */
1770 static int
1771 mlx5_flow_create_action_queue_rss(struct rte_eth_dev *dev,
1772                                   struct mlx5_flow_parse *parser,
1773                                   struct rte_flow *flow,
1774                                   struct rte_flow_error *error)
1775 {
1776         struct priv *priv = dev->data->dev_private;
1777         unsigned int i;
1778
1779         for (i = 0; i != hash_rxq_init_n; ++i) {
1780                 uint64_t hash_fields;
1781
1782                 if (!parser->queue[i].ibv_attr)
1783                         continue;
1784                 flow->frxq[i].ibv_attr = parser->queue[i].ibv_attr;
1785                 parser->queue[i].ibv_attr = NULL;
1786                 hash_fields = hash_rxq_init[i].hash_fields;
1787                 if (!priv->dev->data->dev_started)
1788                         continue;
1789                 flow->frxq[i].hrxq =
1790                         mlx5_hrxq_get(dev,
1791                                       parser->rss_conf.rss_key,
1792                                       parser->rss_conf.rss_key_len,
1793                                       hash_fields,
1794                                       parser->queues,
1795                                       parser->queues_n);
1796                 if (flow->frxq[i].hrxq)
1797                         continue;
1798                 flow->frxq[i].hrxq =
1799                         mlx5_hrxq_new(dev,
1800                                       parser->rss_conf.rss_key,
1801                                       parser->rss_conf.rss_key_len,
1802                                       hash_fields,
1803                                       parser->queues,
1804                                       parser->queues_n);
1805                 if (!flow->frxq[i].hrxq) {
1806                         return rte_flow_error_set(error, ENOMEM,
1807                                                   RTE_FLOW_ERROR_TYPE_HANDLE,
1808                                                   NULL,
1809                                                   "cannot create hash rxq");
1810                 }
1811         }
1812         return 0;
1813 }
1814
1815 /**
1816  * Complete flow rule creation.
1817  *
1818  * @param dev
1819  *   Pointer to Ethernet device.
1820  * @param parser
1821  *   Internal parser structure.
1822  * @param flow
1823  *   Pointer to the rte_flow.
1824  * @param[out] error
1825  *   Perform verbose error reporting if not NULL.
1826  *
1827  * @return
1828  *   0 on success, a negative errno value otherwise and rte_errno is set.
1829  */
1830 static int
1831 mlx5_flow_create_action_queue(struct rte_eth_dev *dev,
1832                               struct mlx5_flow_parse *parser,
1833                               struct rte_flow *flow,
1834                               struct rte_flow_error *error)
1835 {
1836         struct priv *priv = dev->data->dev_private;
1837         int ret;
1838         unsigned int i;
1839         unsigned int flows_n = 0;
1840
1841         assert(priv->pd);
1842         assert(priv->ctx);
1843         assert(!parser->drop);
1844         ret = mlx5_flow_create_action_queue_rss(dev, parser, flow, error);
1845         if (ret)
1846                 goto error;
1847         if (parser->count)
1848                 flow->cs = parser->cs;
1849         if (!priv->dev->data->dev_started)
1850                 return 0;
1851         for (i = 0; i != hash_rxq_init_n; ++i) {
1852                 if (!flow->frxq[i].hrxq)
1853                         continue;
1854                 flow->frxq[i].ibv_flow =
1855                         mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
1856                                                flow->frxq[i].ibv_attr);
1857                 if (!flow->frxq[i].ibv_flow) {
1858                         rte_flow_error_set(error, ENOMEM,
1859                                            RTE_FLOW_ERROR_TYPE_HANDLE,
1860                                            NULL, "flow rule creation failure");
1861                         goto error;
1862                 }
1863                 ++flows_n;
1864                 DRV_LOG(DEBUG, "port %u %p type %d QP %p ibv_flow %p",
1865                         dev->data->port_id,
1866                         (void *)flow, i,
1867                         (void *)flow->frxq[i].hrxq,
1868                         (void *)flow->frxq[i].ibv_flow);
1869         }
1870         if (!flows_n) {
1871                 rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE,
1872                                    NULL, "internal error in flow creation");
1873                 goto error;
1874         }
1875         for (i = 0; i != parser->queues_n; ++i) {
1876                 struct mlx5_rxq_data *q =
1877                         (*priv->rxqs)[parser->queues[i]];
1878
1879                 q->mark |= parser->mark;
1880         }
1881         return 0;
1882 error:
1883         ret = rte_errno; /* Save rte_errno before cleanup. */
1884         assert(flow);
1885         for (i = 0; i != hash_rxq_init_n; ++i) {
1886                 if (flow->frxq[i].ibv_flow) {
1887                         struct ibv_flow *ibv_flow = flow->frxq[i].ibv_flow;
1888
1889                         claim_zero(mlx5_glue->destroy_flow(ibv_flow));
1890                 }
1891                 if (flow->frxq[i].hrxq)
1892                         mlx5_hrxq_release(dev, flow->frxq[i].hrxq);
1893                 if (flow->frxq[i].ibv_attr)
1894                         rte_free(flow->frxq[i].ibv_attr);
1895         }
1896         if (flow->cs) {
1897                 claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
1898                 flow->cs = NULL;
1899                 parser->cs = NULL;
1900         }
1901         rte_errno = ret; /* Restore rte_errno. */
1902         return -rte_errno;
1903 }
1904
1905 /**
1906  * Convert a flow.
1907  *
1908  * @param dev
1909  *   Pointer to Ethernet device.
1910  * @param list
1911  *   Pointer to a TAILQ flow list.
1912  * @param[in] attr
1913  *   Flow rule attributes.
1914  * @param[in] pattern
1915  *   Pattern specification (list terminated by the END pattern item).
1916  * @param[in] actions
1917  *   Associated actions (list terminated by the END action).
1918  * @param[out] error
1919  *   Perform verbose error reporting if not NULL.
1920  *
1921  * @return
1922  *   A flow on success, NULL otherwise and rte_errno is set.
1923  */
1924 static struct rte_flow *
1925 mlx5_flow_list_create(struct rte_eth_dev *dev,
1926                       struct mlx5_flows *list,
1927                       const struct rte_flow_attr *attr,
1928                       const struct rte_flow_item items[],
1929                       const struct rte_flow_action actions[],
1930                       struct rte_flow_error *error)
1931 {
1932         struct mlx5_flow_parse parser = { .create = 1, };
1933         struct rte_flow *flow = NULL;
1934         unsigned int i;
1935         int ret;
1936
1937         ret = mlx5_flow_convert(dev, attr, items, actions, error, &parser);
1938         if (ret)
1939                 goto exit;
1940         flow = rte_calloc(__func__, 1,
1941                           sizeof(*flow) + parser.queues_n * sizeof(uint16_t),
1942                           0);
1943         if (!flow) {
1944                 rte_flow_error_set(error, ENOMEM,
1945                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1946                                    NULL,
1947                                    "cannot allocate flow memory");
1948                 return NULL;
1949         }
1950         /* Copy queues configuration. */
1951         flow->queues = (uint16_t (*)[])(flow + 1);
1952         memcpy(flow->queues, parser.queues, parser.queues_n * sizeof(uint16_t));
1953         flow->queues_n = parser.queues_n;
1954         flow->mark = parser.mark;
1955         /* Copy RSS configuration. */
1956         flow->rss_conf = parser.rss_conf;
1957         flow->rss_conf.rss_key = flow->rss_key;
1958         memcpy(flow->rss_key, parser.rss_key, parser.rss_conf.rss_key_len);
1959         /* finalise the flow. */
1960         if (parser.drop)
1961                 ret = mlx5_flow_create_action_queue_drop(dev, &parser, flow,
1962                                                          error);
1963         else
1964                 ret = mlx5_flow_create_action_queue(dev, &parser, flow, error);
1965         if (ret)
1966                 goto exit;
1967         TAILQ_INSERT_TAIL(list, flow, next);
1968         DRV_LOG(DEBUG, "port %u flow created %p", dev->data->port_id,
1969                 (void *)flow);
1970         return flow;
1971 exit:
1972         DRV_LOG(ERR, "port %u flow creation error: %s", dev->data->port_id,
1973                 error->message);
1974         for (i = 0; i != hash_rxq_init_n; ++i) {
1975                 if (parser.queue[i].ibv_attr)
1976                         rte_free(parser.queue[i].ibv_attr);
1977         }
1978         rte_free(flow);
1979         return NULL;
1980 }
1981
1982 /**
1983  * Validate a flow supported by the NIC.
1984  *
1985  * @see rte_flow_validate()
1986  * @see rte_flow_ops
1987  */
1988 int
1989 mlx5_flow_validate(struct rte_eth_dev *dev,
1990                    const struct rte_flow_attr *attr,
1991                    const struct rte_flow_item items[],
1992                    const struct rte_flow_action actions[],
1993                    struct rte_flow_error *error)
1994 {
1995         struct mlx5_flow_parse parser = { .create = 0, };
1996
1997         return mlx5_flow_convert(dev, attr, items, actions, error, &parser);
1998 }
1999
2000 /**
2001  * Create a flow.
2002  *
2003  * @see rte_flow_create()
2004  * @see rte_flow_ops
2005  */
2006 struct rte_flow *
2007 mlx5_flow_create(struct rte_eth_dev *dev,
2008                  const struct rte_flow_attr *attr,
2009                  const struct rte_flow_item items[],
2010                  const struct rte_flow_action actions[],
2011                  struct rte_flow_error *error)
2012 {
2013         struct priv *priv = dev->data->dev_private;
2014
2015         return mlx5_flow_list_create(dev, &priv->flows, attr, items, actions,
2016                                      error);
2017 }
2018
2019 /**
2020  * Destroy a flow in a list.
2021  *
2022  * @param dev
2023  *   Pointer to Ethernet device.
2024  * @param list
2025  *   Pointer to a TAILQ flow list.
2026  * @param[in] flow
2027  *   Flow to destroy.
2028  */
2029 static void
2030 mlx5_flow_list_destroy(struct rte_eth_dev *dev, struct mlx5_flows *list,
2031                        struct rte_flow *flow)
2032 {
2033         struct priv *priv = dev->data->dev_private;
2034         unsigned int i;
2035
2036         if (flow->drop || !flow->mark)
2037                 goto free;
2038         for (i = 0; i != flow->queues_n; ++i) {
2039                 struct rte_flow *tmp;
2040                 int mark = 0;
2041
2042                 /*
2043                  * To remove the mark from the queue, the queue must not be
2044                  * present in any other marked flow (RSS or not).
2045                  */
2046                 TAILQ_FOREACH(tmp, list, next) {
2047                         unsigned int j;
2048                         uint16_t *tqs = NULL;
2049                         uint16_t tq_n = 0;
2050
2051                         if (!tmp->mark)
2052                                 continue;
2053                         for (j = 0; j != hash_rxq_init_n; ++j) {
2054                                 if (!tmp->frxq[j].hrxq)
2055                                         continue;
2056                                 tqs = tmp->frxq[j].hrxq->ind_table->queues;
2057                                 tq_n = tmp->frxq[j].hrxq->ind_table->queues_n;
2058                         }
2059                         if (!tq_n)
2060                                 continue;
2061                         for (j = 0; (j != tq_n) && !mark; j++)
2062                                 if (tqs[j] == (*flow->queues)[i])
2063                                         mark = 1;
2064                 }
2065                 (*priv->rxqs)[(*flow->queues)[i]]->mark = mark;
2066         }
2067 free:
2068         if (flow->drop) {
2069                 if (flow->frxq[HASH_RXQ_ETH].ibv_flow)
2070                         claim_zero(mlx5_glue->destroy_flow
2071                                    (flow->frxq[HASH_RXQ_ETH].ibv_flow));
2072                 rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
2073         } else {
2074                 for (i = 0; i != hash_rxq_init_n; ++i) {
2075                         struct mlx5_flow *frxq = &flow->frxq[i];
2076
2077                         if (frxq->ibv_flow)
2078                                 claim_zero(mlx5_glue->destroy_flow
2079                                            (frxq->ibv_flow));
2080                         if (frxq->hrxq)
2081                                 mlx5_hrxq_release(dev, frxq->hrxq);
2082                         if (frxq->ibv_attr)
2083                                 rte_free(frxq->ibv_attr);
2084                 }
2085         }
2086         if (flow->cs) {
2087                 claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
2088                 flow->cs = NULL;
2089         }
2090         TAILQ_REMOVE(list, flow, next);
2091         DRV_LOG(DEBUG, "port %u flow destroyed %p", dev->data->port_id,
2092                 (void *)flow);
2093         rte_free(flow);
2094 }
2095
2096 /**
2097  * Destroy all flows.
2098  *
2099  * @param dev
2100  *   Pointer to Ethernet device.
2101  * @param list
2102  *   Pointer to a TAILQ flow list.
2103  */
2104 void
2105 mlx5_flow_list_flush(struct rte_eth_dev *dev, struct mlx5_flows *list)
2106 {
2107         while (!TAILQ_EMPTY(list)) {
2108                 struct rte_flow *flow;
2109
2110                 flow = TAILQ_FIRST(list);
2111                 mlx5_flow_list_destroy(dev, list, flow);
2112         }
2113 }
2114
2115 /**
2116  * Create drop queue.
2117  *
2118  * @param dev
2119  *   Pointer to Ethernet device.
2120  *
2121  * @return
2122  *   0 on success, a negative errno value otherwise and rte_errno is set.
2123  */
2124 int
2125 mlx5_flow_create_drop_queue(struct rte_eth_dev *dev)
2126 {
2127         struct priv *priv = dev->data->dev_private;
2128         struct mlx5_hrxq_drop *fdq = NULL;
2129
2130         assert(priv->pd);
2131         assert(priv->ctx);
2132         fdq = rte_calloc(__func__, 1, sizeof(*fdq), 0);
2133         if (!fdq) {
2134                 DRV_LOG(WARNING,
2135                         "port %u cannot allocate memory for drop queue",
2136                         dev->data->port_id);
2137                 rte_errno = ENOMEM;
2138                 return -rte_errno;
2139         }
2140         fdq->cq = mlx5_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
2141         if (!fdq->cq) {
2142                 DRV_LOG(WARNING, "port %u cannot allocate CQ for drop queue",
2143                         dev->data->port_id);
2144                 rte_errno = errno;
2145                 goto error;
2146         }
2147         fdq->wq = mlx5_glue->create_wq
2148                 (priv->ctx,
2149                  &(struct ibv_wq_init_attr){
2150                         .wq_type = IBV_WQT_RQ,
2151                         .max_wr = 1,
2152                         .max_sge = 1,
2153                         .pd = priv->pd,
2154                         .cq = fdq->cq,
2155                  });
2156         if (!fdq->wq) {
2157                 DRV_LOG(WARNING, "port %u cannot allocate WQ for drop queue",
2158                         dev->data->port_id);
2159                 rte_errno = errno;
2160                 goto error;
2161         }
2162         fdq->ind_table = mlx5_glue->create_rwq_ind_table
2163                 (priv->ctx,
2164                  &(struct ibv_rwq_ind_table_init_attr){
2165                         .log_ind_tbl_size = 0,
2166                         .ind_tbl = &fdq->wq,
2167                         .comp_mask = 0,
2168                  });
2169         if (!fdq->ind_table) {
2170                 DRV_LOG(WARNING,
2171                         "port %u cannot allocate indirection table for drop"
2172                         " queue",
2173                         dev->data->port_id);
2174                 rte_errno = errno;
2175                 goto error;
2176         }
2177         fdq->qp = mlx5_glue->create_qp_ex
2178                 (priv->ctx,
2179                  &(struct ibv_qp_init_attr_ex){
2180                         .qp_type = IBV_QPT_RAW_PACKET,
2181                         .comp_mask =
2182                                 IBV_QP_INIT_ATTR_PD |
2183                                 IBV_QP_INIT_ATTR_IND_TABLE |
2184                                 IBV_QP_INIT_ATTR_RX_HASH,
2185                         .rx_hash_conf = (struct ibv_rx_hash_conf){
2186                                 .rx_hash_function =
2187                                         IBV_RX_HASH_FUNC_TOEPLITZ,
2188                                 .rx_hash_key_len = rss_hash_default_key_len,
2189                                 .rx_hash_key = rss_hash_default_key,
2190                                 .rx_hash_fields_mask = 0,
2191                                 },
2192                         .rwq_ind_tbl = fdq->ind_table,
2193                         .pd = priv->pd
2194                  });
2195         if (!fdq->qp) {
2196                 DRV_LOG(WARNING, "port %u cannot allocate QP for drop queue",
2197                         dev->data->port_id);
2198                 rte_errno = errno;
2199                 goto error;
2200         }
2201         priv->flow_drop_queue = fdq;
2202         return 0;
2203 error:
2204         if (fdq->qp)
2205                 claim_zero(mlx5_glue->destroy_qp(fdq->qp));
2206         if (fdq->ind_table)
2207                 claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
2208         if (fdq->wq)
2209                 claim_zero(mlx5_glue->destroy_wq(fdq->wq));
2210         if (fdq->cq)
2211                 claim_zero(mlx5_glue->destroy_cq(fdq->cq));
2212         if (fdq)
2213                 rte_free(fdq);
2214         priv->flow_drop_queue = NULL;
2215         return -rte_errno;
2216 }
2217
2218 /**
2219  * Delete drop queue.
2220  *
2221  * @param dev
2222  *   Pointer to Ethernet device.
2223  */
2224 void
2225 mlx5_flow_delete_drop_queue(struct rte_eth_dev *dev)
2226 {
2227         struct priv *priv = dev->data->dev_private;
2228         struct mlx5_hrxq_drop *fdq = priv->flow_drop_queue;
2229
2230         if (!fdq)
2231                 return;
2232         if (fdq->qp)
2233                 claim_zero(mlx5_glue->destroy_qp(fdq->qp));
2234         if (fdq->ind_table)
2235                 claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
2236         if (fdq->wq)
2237                 claim_zero(mlx5_glue->destroy_wq(fdq->wq));
2238         if (fdq->cq)
2239                 claim_zero(mlx5_glue->destroy_cq(fdq->cq));
2240         rte_free(fdq);
2241         priv->flow_drop_queue = NULL;
2242 }
2243
2244 /**
2245  * Remove all flows.
2246  *
2247  * @param dev
2248  *   Pointer to Ethernet device.
2249  * @param list
2250  *   Pointer to a TAILQ flow list.
2251  */
2252 void
2253 mlx5_flow_stop(struct rte_eth_dev *dev, struct mlx5_flows *list)
2254 {
2255         struct priv *priv = dev->data->dev_private;
2256         struct rte_flow *flow;
2257
2258         TAILQ_FOREACH_REVERSE(flow, list, mlx5_flows, next) {
2259                 unsigned int i;
2260                 struct mlx5_ind_table_ibv *ind_tbl = NULL;
2261
2262                 if (flow->drop) {
2263                         if (!flow->frxq[HASH_RXQ_ETH].ibv_flow)
2264                                 continue;
2265                         claim_zero(mlx5_glue->destroy_flow
2266                                    (flow->frxq[HASH_RXQ_ETH].ibv_flow));
2267                         flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
2268                         DRV_LOG(DEBUG, "port %u flow %p removed",
2269                                 dev->data->port_id, (void *)flow);
2270                         /* Next flow. */
2271                         continue;
2272                 }
2273                 /* Verify the flow has not already been cleaned. */
2274                 for (i = 0; i != hash_rxq_init_n; ++i) {
2275                         if (!flow->frxq[i].ibv_flow)
2276                                 continue;
2277                         /*
2278                          * Indirection table may be necessary to remove the
2279                          * flags in the Rx queues.
2280                          * This helps to speed-up the process by avoiding
2281                          * another loop.
2282                          */
2283                         ind_tbl = flow->frxq[i].hrxq->ind_table;
2284                         break;
2285                 }
2286                 if (i == hash_rxq_init_n)
2287                         return;
2288                 if (flow->mark) {
2289                         assert(ind_tbl);
2290                         for (i = 0; i != ind_tbl->queues_n; ++i)
2291                                 (*priv->rxqs)[ind_tbl->queues[i]]->mark = 0;
2292                 }
2293                 for (i = 0; i != hash_rxq_init_n; ++i) {
2294                         if (!flow->frxq[i].ibv_flow)
2295                                 continue;
2296                         claim_zero(mlx5_glue->destroy_flow
2297                                    (flow->frxq[i].ibv_flow));
2298                         flow->frxq[i].ibv_flow = NULL;
2299                         mlx5_hrxq_release(dev, flow->frxq[i].hrxq);
2300                         flow->frxq[i].hrxq = NULL;
2301                 }
2302                 DRV_LOG(DEBUG, "port %u flow %p removed", dev->data->port_id,
2303                         (void *)flow);
2304         }
2305 }
2306
2307 /**
2308  * Add all flows.
2309  *
2310  * @param dev
2311  *   Pointer to Ethernet device.
2312  * @param list
2313  *   Pointer to a TAILQ flow list.
2314  *
2315  * @return
2316  *   0 on success, a negative errno value otherwise and rte_errno is set.
2317  */
2318 int
2319 mlx5_flow_start(struct rte_eth_dev *dev, struct mlx5_flows *list)
2320 {
2321         struct priv *priv = dev->data->dev_private;
2322         struct rte_flow *flow;
2323
2324         TAILQ_FOREACH(flow, list, next) {
2325                 unsigned int i;
2326
2327                 if (flow->drop) {
2328                         flow->frxq[HASH_RXQ_ETH].ibv_flow =
2329                                 mlx5_glue->create_flow
2330                                 (priv->flow_drop_queue->qp,
2331                                  flow->frxq[HASH_RXQ_ETH].ibv_attr);
2332                         if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
2333                                 DRV_LOG(DEBUG,
2334                                         "port %u flow %p cannot be applied",
2335                                         dev->data->port_id, (void *)flow);
2336                                 rte_errno = EINVAL;
2337                                 return -rte_errno;
2338                         }
2339                         DRV_LOG(DEBUG, "port %u flow %p applied",
2340                                 dev->data->port_id, (void *)flow);
2341                         /* Next flow. */
2342                         continue;
2343                 }
2344                 for (i = 0; i != hash_rxq_init_n; ++i) {
2345                         if (!flow->frxq[i].ibv_attr)
2346                                 continue;
2347                         flow->frxq[i].hrxq =
2348                                 mlx5_hrxq_get(dev, flow->rss_conf.rss_key,
2349                                               flow->rss_conf.rss_key_len,
2350                                               hash_rxq_init[i].hash_fields,
2351                                               (*flow->queues),
2352                                               flow->queues_n);
2353                         if (flow->frxq[i].hrxq)
2354                                 goto flow_create;
2355                         flow->frxq[i].hrxq =
2356                                 mlx5_hrxq_new(dev, flow->rss_conf.rss_key,
2357                                               flow->rss_conf.rss_key_len,
2358                                               hash_rxq_init[i].hash_fields,
2359                                               (*flow->queues),
2360                                               flow->queues_n);
2361                         if (!flow->frxq[i].hrxq) {
2362                                 DRV_LOG(DEBUG,
2363                                         "port %u flow %p cannot be applied",
2364                                         dev->data->port_id, (void *)flow);
2365                                 rte_errno = EINVAL;
2366                                 return -rte_errno;
2367                         }
2368 flow_create:
2369                         flow->frxq[i].ibv_flow =
2370                                 mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
2371                                                        flow->frxq[i].ibv_attr);
2372                         if (!flow->frxq[i].ibv_flow) {
2373                                 DRV_LOG(DEBUG,
2374                                         "port %u flow %p cannot be applied",
2375                                         dev->data->port_id, (void *)flow);
2376                                 rte_errno = EINVAL;
2377                                 return -rte_errno;
2378                         }
2379                         DRV_LOG(DEBUG, "port %u flow %p applied",
2380                                 dev->data->port_id, (void *)flow);
2381                 }
2382                 if (!flow->mark)
2383                         continue;
2384                 for (i = 0; i != flow->queues_n; ++i)
2385                         (*priv->rxqs)[(*flow->queues)[i]]->mark = 1;
2386         }
2387         return 0;
2388 }
2389
2390 /**
2391  * Verify the flow list is empty
2392  *
2393  * @param dev
2394  *  Pointer to Ethernet device.
2395  *
2396  * @return the number of flows not released.
2397  */
2398 int
2399 mlx5_flow_verify(struct rte_eth_dev *dev)
2400 {
2401         struct priv *priv = dev->data->dev_private;
2402         struct rte_flow *flow;
2403         int ret = 0;
2404
2405         TAILQ_FOREACH(flow, &priv->flows, next) {
2406                 DRV_LOG(DEBUG, "port %u flow %p still referenced",
2407                         dev->data->port_id, (void *)flow);
2408                 ++ret;
2409         }
2410         return ret;
2411 }
2412
2413 /**
2414  * Enable a control flow configured from the control plane.
2415  *
2416  * @param dev
2417  *   Pointer to Ethernet device.
2418  * @param eth_spec
2419  *   An Ethernet flow spec to apply.
2420  * @param eth_mask
2421  *   An Ethernet flow mask to apply.
2422  * @param vlan_spec
2423  *   A VLAN flow spec to apply.
2424  * @param vlan_mask
2425  *   A VLAN flow mask to apply.
2426  *
2427  * @return
2428  *   0 on success, a negative errno value otherwise and rte_errno is set.
2429  */
2430 int
2431 mlx5_ctrl_flow_vlan(struct rte_eth_dev *dev,
2432                     struct rte_flow_item_eth *eth_spec,
2433                     struct rte_flow_item_eth *eth_mask,
2434                     struct rte_flow_item_vlan *vlan_spec,
2435                     struct rte_flow_item_vlan *vlan_mask)
2436 {
2437         struct priv *priv = dev->data->dev_private;
2438         const struct rte_flow_attr attr = {
2439                 .ingress = 1,
2440                 .priority = MLX5_CTRL_FLOW_PRIORITY,
2441         };
2442         struct rte_flow_item items[] = {
2443                 {
2444                         .type = RTE_FLOW_ITEM_TYPE_ETH,
2445                         .spec = eth_spec,
2446                         .last = NULL,
2447                         .mask = eth_mask,
2448                 },
2449                 {
2450                         .type = (vlan_spec) ? RTE_FLOW_ITEM_TYPE_VLAN :
2451                                 RTE_FLOW_ITEM_TYPE_END,
2452                         .spec = vlan_spec,
2453                         .last = NULL,
2454                         .mask = vlan_mask,
2455                 },
2456                 {
2457                         .type = RTE_FLOW_ITEM_TYPE_END,
2458                 },
2459         };
2460         struct rte_flow_action actions[] = {
2461                 {
2462                         .type = RTE_FLOW_ACTION_TYPE_RSS,
2463                 },
2464                 {
2465                         .type = RTE_FLOW_ACTION_TYPE_END,
2466                 },
2467         };
2468         struct rte_flow *flow;
2469         struct rte_flow_error error;
2470         unsigned int i;
2471         union {
2472                 struct rte_flow_action_rss rss;
2473                 struct {
2474                         const struct rte_eth_rss_conf *rss_conf;
2475                         uint16_t num;
2476                         uint16_t queue[RTE_MAX_QUEUES_PER_PORT];
2477                 } local;
2478         } action_rss;
2479
2480         if (!priv->reta_idx_n) {
2481                 rte_errno = EINVAL;
2482                 return -rte_errno;
2483         }
2484         for (i = 0; i != priv->reta_idx_n; ++i)
2485                 action_rss.local.queue[i] = (*priv->reta_idx)[i];
2486         action_rss.local.rss_conf = &priv->rss_conf;
2487         action_rss.local.num = priv->reta_idx_n;
2488         actions[0].conf = (const void *)&action_rss.rss;
2489         flow = mlx5_flow_list_create(dev, &priv->ctrl_flows, &attr, items,
2490                                      actions, &error);
2491         if (!flow)
2492                 return -rte_errno;
2493         return 0;
2494 }
2495
2496 /**
2497  * Enable a flow control configured from the control plane.
2498  *
2499  * @param dev
2500  *   Pointer to Ethernet device.
2501  * @param eth_spec
2502  *   An Ethernet flow spec to apply.
2503  * @param eth_mask
2504  *   An Ethernet flow mask to apply.
2505  *
2506  * @return
2507  *   0 on success, a negative errno value otherwise and rte_errno is set.
2508  */
2509 int
2510 mlx5_ctrl_flow(struct rte_eth_dev *dev,
2511                struct rte_flow_item_eth *eth_spec,
2512                struct rte_flow_item_eth *eth_mask)
2513 {
2514         return mlx5_ctrl_flow_vlan(dev, eth_spec, eth_mask, NULL, NULL);
2515 }
2516
2517 /**
2518  * Destroy a flow.
2519  *
2520  * @see rte_flow_destroy()
2521  * @see rte_flow_ops
2522  */
2523 int
2524 mlx5_flow_destroy(struct rte_eth_dev *dev,
2525                   struct rte_flow *flow,
2526                   struct rte_flow_error *error __rte_unused)
2527 {
2528         struct priv *priv = dev->data->dev_private;
2529
2530         mlx5_flow_list_destroy(dev, &priv->flows, flow);
2531         return 0;
2532 }
2533
2534 /**
2535  * Destroy all flows.
2536  *
2537  * @see rte_flow_flush()
2538  * @see rte_flow_ops
2539  */
2540 int
2541 mlx5_flow_flush(struct rte_eth_dev *dev,
2542                 struct rte_flow_error *error __rte_unused)
2543 {
2544         struct priv *priv = dev->data->dev_private;
2545
2546         mlx5_flow_list_flush(dev, &priv->flows);
2547         return 0;
2548 }
2549
2550 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
2551 /**
2552  * Query flow counter.
2553  *
2554  * @param cs
2555  *   the counter set.
2556  * @param counter_value
2557  *   returned data from the counter.
2558  *
2559  * @return
2560  *   0 on success, a negative errno value otherwise and rte_errno is set.
2561  */
2562 static int
2563 mlx5_flow_query_count(struct ibv_counter_set *cs,
2564                       struct mlx5_flow_counter_stats *counter_stats,
2565                       struct rte_flow_query_count *query_count,
2566                       struct rte_flow_error *error)
2567 {
2568         uint64_t counters[2];
2569         struct ibv_query_counter_set_attr query_cs_attr = {
2570                 .cs = cs,
2571                 .query_flags = IBV_COUNTER_SET_FORCE_UPDATE,
2572         };
2573         struct ibv_counter_set_data query_out = {
2574                 .out = counters,
2575                 .outlen = 2 * sizeof(uint64_t),
2576         };
2577         int err = mlx5_glue->query_counter_set(&query_cs_attr, &query_out);
2578
2579         if (err)
2580                 return rte_flow_error_set(error, err,
2581                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2582                                           NULL,
2583                                           "cannot read counter");
2584         query_count->hits_set = 1;
2585         query_count->bytes_set = 1;
2586         query_count->hits = counters[0] - counter_stats->hits;
2587         query_count->bytes = counters[1] - counter_stats->bytes;
2588         if (query_count->reset) {
2589                 counter_stats->hits = counters[0];
2590                 counter_stats->bytes = counters[1];
2591         }
2592         return 0;
2593 }
2594
2595 /**
2596  * Query a flows.
2597  *
2598  * @see rte_flow_query()
2599  * @see rte_flow_ops
2600  */
2601 int
2602 mlx5_flow_query(struct rte_eth_dev *dev __rte_unused,
2603                 struct rte_flow *flow,
2604                 enum rte_flow_action_type action __rte_unused,
2605                 void *data,
2606                 struct rte_flow_error *error)
2607 {
2608         if (flow->cs) {
2609                 int ret;
2610
2611                 ret = mlx5_flow_query_count(flow->cs,
2612                                             &flow->counter_stats,
2613                                             (struct rte_flow_query_count *)data,
2614                                             error);
2615                 if (ret)
2616                         return ret;
2617         } else {
2618                 return rte_flow_error_set(error, EINVAL,
2619                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2620                                           NULL,
2621                                           "no counter found for flow");
2622         }
2623         return 0;
2624 }
2625 #endif
2626
2627 /**
2628  * Isolated mode.
2629  *
2630  * @see rte_flow_isolate()
2631  * @see rte_flow_ops
2632  */
2633 int
2634 mlx5_flow_isolate(struct rte_eth_dev *dev,
2635                   int enable,
2636                   struct rte_flow_error *error)
2637 {
2638         struct priv *priv = dev->data->dev_private;
2639
2640         if (dev->data->dev_started) {
2641                 rte_flow_error_set(error, EBUSY,
2642                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2643                                    NULL,
2644                                    "port must be stopped first");
2645                 return -rte_errno;
2646         }
2647         priv->isolated = !!enable;
2648         if (enable)
2649                 priv->dev->dev_ops = &mlx5_dev_ops_isolate;
2650         else
2651                 priv->dev->dev_ops = &mlx5_dev_ops;
2652         return 0;
2653 }
2654
2655 /**
2656  * Convert a flow director filter to a generic flow.
2657  *
2658  * @param dev
2659  *   Pointer to Ethernet device.
2660  * @param fdir_filter
2661  *   Flow director filter to add.
2662  * @param attributes
2663  *   Generic flow parameters structure.
2664  *
2665  * @return
2666  *   0 on success, a negative errno value otherwise and rte_errno is set.
2667  */
2668 static int
2669 mlx5_fdir_filter_convert(struct rte_eth_dev *dev,
2670                          const struct rte_eth_fdir_filter *fdir_filter,
2671                          struct mlx5_fdir *attributes)
2672 {
2673         struct priv *priv = dev->data->dev_private;
2674         const struct rte_eth_fdir_input *input = &fdir_filter->input;
2675
2676         /* Validate queue number. */
2677         if (fdir_filter->action.rx_queue >= priv->rxqs_n) {
2678                 DRV_LOG(ERR, "port %u invalid queue number %d",
2679                         dev->data->port_id, fdir_filter->action.rx_queue);
2680                 rte_errno = EINVAL;
2681                 return -rte_errno;
2682         }
2683         attributes->attr.ingress = 1;
2684         attributes->items[0] = (struct rte_flow_item) {
2685                 .type = RTE_FLOW_ITEM_TYPE_ETH,
2686                 .spec = &attributes->l2,
2687                 .mask = &attributes->l2_mask,
2688         };
2689         switch (fdir_filter->action.behavior) {
2690         case RTE_ETH_FDIR_ACCEPT:
2691                 attributes->actions[0] = (struct rte_flow_action){
2692                         .type = RTE_FLOW_ACTION_TYPE_QUEUE,
2693                         .conf = &attributes->queue,
2694                 };
2695                 break;
2696         case RTE_ETH_FDIR_REJECT:
2697                 attributes->actions[0] = (struct rte_flow_action){
2698                         .type = RTE_FLOW_ACTION_TYPE_DROP,
2699                 };
2700                 break;
2701         default:
2702                 DRV_LOG(ERR, "port %u invalid behavior %d",
2703                         dev->data->port_id,
2704                         fdir_filter->action.behavior);
2705                 rte_errno = ENOTSUP;
2706                 return -rte_errno;
2707         }
2708         attributes->queue.index = fdir_filter->action.rx_queue;
2709         switch (fdir_filter->input.flow_type) {
2710         case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
2711                 attributes->l3.ipv4.hdr = (struct ipv4_hdr){
2712                         .src_addr = input->flow.udp4_flow.ip.src_ip,
2713                         .dst_addr = input->flow.udp4_flow.ip.dst_ip,
2714                         .time_to_live = input->flow.udp4_flow.ip.ttl,
2715                         .type_of_service = input->flow.udp4_flow.ip.tos,
2716                         .next_proto_id = input->flow.udp4_flow.ip.proto,
2717                 };
2718                 attributes->l4.udp.hdr = (struct udp_hdr){
2719                         .src_port = input->flow.udp4_flow.src_port,
2720                         .dst_port = input->flow.udp4_flow.dst_port,
2721                 };
2722                 attributes->items[1] = (struct rte_flow_item){
2723                         .type = RTE_FLOW_ITEM_TYPE_IPV4,
2724                         .spec = &attributes->l3,
2725                         .mask = &attributes->l3,
2726                 };
2727                 attributes->items[2] = (struct rte_flow_item){
2728                         .type = RTE_FLOW_ITEM_TYPE_UDP,
2729                         .spec = &attributes->l4,
2730                         .mask = &attributes->l4,
2731                 };
2732                 break;
2733         case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
2734                 attributes->l3.ipv4.hdr = (struct ipv4_hdr){
2735                         .src_addr = input->flow.tcp4_flow.ip.src_ip,
2736                         .dst_addr = input->flow.tcp4_flow.ip.dst_ip,
2737                         .time_to_live = input->flow.tcp4_flow.ip.ttl,
2738                         .type_of_service = input->flow.tcp4_flow.ip.tos,
2739                         .next_proto_id = input->flow.tcp4_flow.ip.proto,
2740                 };
2741                 attributes->l4.tcp.hdr = (struct tcp_hdr){
2742                         .src_port = input->flow.tcp4_flow.src_port,
2743                         .dst_port = input->flow.tcp4_flow.dst_port,
2744                 };
2745                 attributes->items[1] = (struct rte_flow_item){
2746                         .type = RTE_FLOW_ITEM_TYPE_IPV4,
2747                         .spec = &attributes->l3,
2748                         .mask = &attributes->l3,
2749                 };
2750                 attributes->items[2] = (struct rte_flow_item){
2751                         .type = RTE_FLOW_ITEM_TYPE_TCP,
2752                         .spec = &attributes->l4,
2753                         .mask = &attributes->l4,
2754                 };
2755                 break;
2756         case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
2757                 attributes->l3.ipv4.hdr = (struct ipv4_hdr){
2758                         .src_addr = input->flow.ip4_flow.src_ip,
2759                         .dst_addr = input->flow.ip4_flow.dst_ip,
2760                         .time_to_live = input->flow.ip4_flow.ttl,
2761                         .type_of_service = input->flow.ip4_flow.tos,
2762                         .next_proto_id = input->flow.ip4_flow.proto,
2763                 };
2764                 attributes->items[1] = (struct rte_flow_item){
2765                         .type = RTE_FLOW_ITEM_TYPE_IPV4,
2766                         .spec = &attributes->l3,
2767                         .mask = &attributes->l3,
2768                 };
2769                 break;
2770         case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
2771                 attributes->l3.ipv6.hdr = (struct ipv6_hdr){
2772                         .hop_limits = input->flow.udp6_flow.ip.hop_limits,
2773                         .proto = input->flow.udp6_flow.ip.proto,
2774                 };
2775                 memcpy(attributes->l3.ipv6.hdr.src_addr,
2776                        input->flow.udp6_flow.ip.src_ip,
2777                        RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
2778                 memcpy(attributes->l3.ipv6.hdr.dst_addr,
2779                        input->flow.udp6_flow.ip.dst_ip,
2780                        RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
2781                 attributes->l4.udp.hdr = (struct udp_hdr){
2782                         .src_port = input->flow.udp6_flow.src_port,
2783                         .dst_port = input->flow.udp6_flow.dst_port,
2784                 };
2785                 attributes->items[1] = (struct rte_flow_item){
2786                         .type = RTE_FLOW_ITEM_TYPE_IPV6,
2787                         .spec = &attributes->l3,
2788                         .mask = &attributes->l3,
2789                 };
2790                 attributes->items[2] = (struct rte_flow_item){
2791                         .type = RTE_FLOW_ITEM_TYPE_UDP,
2792                         .spec = &attributes->l4,
2793                         .mask = &attributes->l4,
2794                 };
2795                 break;
2796         case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
2797                 attributes->l3.ipv6.hdr = (struct ipv6_hdr){
2798                         .hop_limits = input->flow.tcp6_flow.ip.hop_limits,
2799                         .proto = input->flow.tcp6_flow.ip.proto,
2800                 };
2801                 memcpy(attributes->l3.ipv6.hdr.src_addr,
2802                        input->flow.tcp6_flow.ip.src_ip,
2803                        RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
2804                 memcpy(attributes->l3.ipv6.hdr.dst_addr,
2805                        input->flow.tcp6_flow.ip.dst_ip,
2806                        RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
2807                 attributes->l4.tcp.hdr = (struct tcp_hdr){
2808                         .src_port = input->flow.tcp6_flow.src_port,
2809                         .dst_port = input->flow.tcp6_flow.dst_port,
2810                 };
2811                 attributes->items[1] = (struct rte_flow_item){
2812                         .type = RTE_FLOW_ITEM_TYPE_IPV6,
2813                         .spec = &attributes->l3,
2814                         .mask = &attributes->l3,
2815                 };
2816                 attributes->items[2] = (struct rte_flow_item){
2817                         .type = RTE_FLOW_ITEM_TYPE_TCP,
2818                         .spec = &attributes->l4,
2819                         .mask = &attributes->l4,
2820                 };
2821                 break;
2822         case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
2823                 attributes->l3.ipv6.hdr = (struct ipv6_hdr){
2824                         .hop_limits = input->flow.ipv6_flow.hop_limits,
2825                         .proto = input->flow.ipv6_flow.proto,
2826                 };
2827                 memcpy(attributes->l3.ipv6.hdr.src_addr,
2828                        input->flow.ipv6_flow.src_ip,
2829                        RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
2830                 memcpy(attributes->l3.ipv6.hdr.dst_addr,
2831                        input->flow.ipv6_flow.dst_ip,
2832                        RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
2833                 attributes->items[1] = (struct rte_flow_item){
2834                         .type = RTE_FLOW_ITEM_TYPE_IPV6,
2835                         .spec = &attributes->l3,
2836                         .mask = &attributes->l3,
2837                 };
2838                 break;
2839         default:
2840                 DRV_LOG(ERR, "port %u invalid flow type%d",
2841                         dev->data->port_id, fdir_filter->input.flow_type);
2842                 rte_errno = ENOTSUP;
2843                 return -rte_errno;
2844         }
2845         return 0;
2846 }
2847
2848 /**
2849  * Add new flow director filter and store it in list.
2850  *
2851  * @param dev
2852  *   Pointer to Ethernet device.
2853  * @param fdir_filter
2854  *   Flow director filter to add.
2855  *
2856  * @return
2857  *   0 on success, a negative errno value otherwise and rte_errno is set.
2858  */
2859 static int
2860 mlx5_fdir_filter_add(struct rte_eth_dev *dev,
2861                      const struct rte_eth_fdir_filter *fdir_filter)
2862 {
2863         struct priv *priv = dev->data->dev_private;
2864         struct mlx5_fdir attributes = {
2865                 .attr.group = 0,
2866                 .l2_mask = {
2867                         .dst.addr_bytes = "\x00\x00\x00\x00\x00\x00",
2868                         .src.addr_bytes = "\x00\x00\x00\x00\x00\x00",
2869                         .type = 0,
2870                 },
2871         };
2872         struct mlx5_flow_parse parser = {
2873                 .layer = HASH_RXQ_ETH,
2874         };
2875         struct rte_flow_error error;
2876         struct rte_flow *flow;
2877         int ret;
2878
2879         ret = mlx5_fdir_filter_convert(dev, fdir_filter, &attributes);
2880         if (ret)
2881                 return ret;
2882         ret = mlx5_flow_convert(dev, &attributes.attr, attributes.items,
2883                                 attributes.actions, &error, &parser);
2884         if (ret)
2885                 return ret;
2886         flow = mlx5_flow_list_create(dev, &priv->flows, &attributes.attr,
2887                                      attributes.items, attributes.actions,
2888                                      &error);
2889         if (flow) {
2890                 DRV_LOG(DEBUG, "port %u FDIR created %p", dev->data->port_id,
2891                         (void *)flow);
2892                 return 0;
2893         }
2894         return -rte_errno;
2895 }
2896
2897 /**
2898  * Delete specific filter.
2899  *
2900  * @param dev
2901  *   Pointer to Ethernet device.
2902  * @param fdir_filter
2903  *   Filter to be deleted.
2904  *
2905  * @return
2906  *   0 on success, a negative errno value otherwise and rte_errno is set.
2907  */
2908 static int
2909 mlx5_fdir_filter_delete(struct rte_eth_dev *dev,
2910                         const struct rte_eth_fdir_filter *fdir_filter)
2911 {
2912         struct priv *priv = dev->data->dev_private;
2913         struct mlx5_fdir attributes = {
2914                 .attr.group = 0,
2915         };
2916         struct mlx5_flow_parse parser = {
2917                 .create = 1,
2918                 .layer = HASH_RXQ_ETH,
2919         };
2920         struct rte_flow_error error;
2921         struct rte_flow *flow;
2922         unsigned int i;
2923         int ret;
2924
2925         ret = mlx5_fdir_filter_convert(dev, fdir_filter, &attributes);
2926         if (ret)
2927                 return ret;
2928         ret = mlx5_flow_convert(dev, &attributes.attr, attributes.items,
2929                                 attributes.actions, &error, &parser);
2930         if (ret)
2931                 goto exit;
2932         /*
2933          * Special case for drop action which is only set in the
2934          * specifications when the flow is created.  In this situation the
2935          * drop specification is missing.
2936          */
2937         if (parser.drop) {
2938                 struct ibv_flow_spec_action_drop *drop;
2939
2940                 drop = (void *)((uintptr_t)parser.queue[HASH_RXQ_ETH].ibv_attr +
2941                                 parser.queue[HASH_RXQ_ETH].offset);
2942                 *drop = (struct ibv_flow_spec_action_drop){
2943                         .type = IBV_FLOW_SPEC_ACTION_DROP,
2944                         .size = sizeof(struct ibv_flow_spec_action_drop),
2945                 };
2946                 parser.queue[HASH_RXQ_ETH].ibv_attr->num_of_specs++;
2947         }
2948         TAILQ_FOREACH(flow, &priv->flows, next) {
2949                 struct ibv_flow_attr *attr;
2950                 struct ibv_spec_header *attr_h;
2951                 void *spec;
2952                 struct ibv_flow_attr *flow_attr;
2953                 struct ibv_spec_header *flow_h;
2954                 void *flow_spec;
2955                 unsigned int specs_n;
2956
2957                 attr = parser.queue[HASH_RXQ_ETH].ibv_attr;
2958                 flow_attr = flow->frxq[HASH_RXQ_ETH].ibv_attr;
2959                 /* Compare first the attributes. */
2960                 if (memcmp(attr, flow_attr, sizeof(struct ibv_flow_attr)))
2961                         continue;
2962                 if (attr->num_of_specs == 0)
2963                         continue;
2964                 spec = (void *)((uintptr_t)attr +
2965                                 sizeof(struct ibv_flow_attr));
2966                 flow_spec = (void *)((uintptr_t)flow_attr +
2967                                      sizeof(struct ibv_flow_attr));
2968                 specs_n = RTE_MIN(attr->num_of_specs, flow_attr->num_of_specs);
2969                 for (i = 0; i != specs_n; ++i) {
2970                         attr_h = spec;
2971                         flow_h = flow_spec;
2972                         if (memcmp(spec, flow_spec,
2973                                    RTE_MIN(attr_h->size, flow_h->size)))
2974                                 goto wrong_flow;
2975                         spec = (void *)((uintptr_t)spec + attr_h->size);
2976                         flow_spec = (void *)((uintptr_t)flow_spec +
2977                                              flow_h->size);
2978                 }
2979                 /* At this point, the flow match. */
2980                 break;
2981 wrong_flow:
2982                 /* The flow does not match. */
2983                 continue;
2984         }
2985         ret = rte_errno; /* Save rte_errno before cleanup. */
2986         if (flow)
2987                 mlx5_flow_list_destroy(dev, &priv->flows, flow);
2988 exit:
2989         for (i = 0; i != hash_rxq_init_n; ++i) {
2990                 if (parser.queue[i].ibv_attr)
2991                         rte_free(parser.queue[i].ibv_attr);
2992         }
2993         rte_errno = ret; /* Restore rte_errno. */
2994         return -rte_errno;
2995 }
2996
2997 /**
2998  * Update queue for specific filter.
2999  *
3000  * @param dev
3001  *   Pointer to Ethernet device.
3002  * @param fdir_filter
3003  *   Filter to be updated.
3004  *
3005  * @return
3006  *   0 on success, a negative errno value otherwise and rte_errno is set.
3007  */
3008 static int
3009 mlx5_fdir_filter_update(struct rte_eth_dev *dev,
3010                         const struct rte_eth_fdir_filter *fdir_filter)
3011 {
3012         int ret;
3013
3014         ret = mlx5_fdir_filter_delete(dev, fdir_filter);
3015         if (ret)
3016                 return ret;
3017         return mlx5_fdir_filter_add(dev, fdir_filter);
3018 }
3019
3020 /**
3021  * Flush all filters.
3022  *
3023  * @param dev
3024  *   Pointer to Ethernet device.
3025  */
3026 static void
3027 mlx5_fdir_filter_flush(struct rte_eth_dev *dev)
3028 {
3029         struct priv *priv = dev->data->dev_private;
3030
3031         mlx5_flow_list_flush(dev, &priv->flows);
3032 }
3033
3034 /**
3035  * Get flow director information.
3036  *
3037  * @param dev
3038  *   Pointer to Ethernet device.
3039  * @param[out] fdir_info
3040  *   Resulting flow director information.
3041  */
3042 static void
3043 mlx5_fdir_info_get(struct rte_eth_dev *dev, struct rte_eth_fdir_info *fdir_info)
3044 {
3045         struct priv *priv = dev->data->dev_private;
3046         struct rte_eth_fdir_masks *mask =
3047                 &priv->dev->data->dev_conf.fdir_conf.mask;
3048
3049         fdir_info->mode = priv->dev->data->dev_conf.fdir_conf.mode;
3050         fdir_info->guarant_spc = 0;
3051         rte_memcpy(&fdir_info->mask, mask, sizeof(fdir_info->mask));
3052         fdir_info->max_flexpayload = 0;
3053         fdir_info->flow_types_mask[0] = 0;
3054         fdir_info->flex_payload_unit = 0;
3055         fdir_info->max_flex_payload_segment_num = 0;
3056         fdir_info->flex_payload_limit = 0;
3057         memset(&fdir_info->flex_conf, 0, sizeof(fdir_info->flex_conf));
3058 }
3059
3060 /**
3061  * Deal with flow director operations.
3062  *
3063  * @param dev
3064  *   Pointer to Ethernet device.
3065  * @param filter_op
3066  *   Operation to perform.
3067  * @param arg
3068  *   Pointer to operation-specific structure.
3069  *
3070  * @return
3071  *   0 on success, a negative errno value otherwise and rte_errno is set.
3072  */
3073 static int
3074 mlx5_fdir_ctrl_func(struct rte_eth_dev *dev, enum rte_filter_op filter_op,
3075                     void *arg)
3076 {
3077         struct priv *priv = dev->data->dev_private;
3078         enum rte_fdir_mode fdir_mode =
3079                 priv->dev->data->dev_conf.fdir_conf.mode;
3080
3081         if (filter_op == RTE_ETH_FILTER_NOP)
3082                 return 0;
3083         if (fdir_mode != RTE_FDIR_MODE_PERFECT &&
3084             fdir_mode != RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
3085                 DRV_LOG(ERR, "port %u flow director mode %d not supported",
3086                         dev->data->port_id, fdir_mode);
3087                 rte_errno = EINVAL;
3088                 return -rte_errno;
3089         }
3090         switch (filter_op) {
3091         case RTE_ETH_FILTER_ADD:
3092                 return mlx5_fdir_filter_add(dev, arg);
3093         case RTE_ETH_FILTER_UPDATE:
3094                 return mlx5_fdir_filter_update(dev, arg);
3095         case RTE_ETH_FILTER_DELETE:
3096                 return mlx5_fdir_filter_delete(dev, arg);
3097         case RTE_ETH_FILTER_FLUSH:
3098                 mlx5_fdir_filter_flush(dev);
3099                 break;
3100         case RTE_ETH_FILTER_INFO:
3101                 mlx5_fdir_info_get(dev, arg);
3102                 break;
3103         default:
3104                 DRV_LOG(DEBUG, "port %u unknown operation %u",
3105                         dev->data->port_id, filter_op);
3106                 rte_errno = EINVAL;
3107                 return -rte_errno;
3108         }
3109         return 0;
3110 }
3111
3112 /**
3113  * Manage filter operations.
3114  *
3115  * @param dev
3116  *   Pointer to Ethernet device structure.
3117  * @param filter_type
3118  *   Filter type.
3119  * @param filter_op
3120  *   Operation to perform.
3121  * @param arg
3122  *   Pointer to operation-specific structure.
3123  *
3124  * @return
3125  *   0 on success, a negative errno value otherwise and rte_errno is set.
3126  */
3127 int
3128 mlx5_dev_filter_ctrl(struct rte_eth_dev *dev,
3129                      enum rte_filter_type filter_type,
3130                      enum rte_filter_op filter_op,
3131                      void *arg)
3132 {
3133         switch (filter_type) {
3134         case RTE_ETH_FILTER_GENERIC:
3135                 if (filter_op != RTE_ETH_FILTER_GET) {
3136                         rte_errno = EINVAL;
3137                         return -rte_errno;
3138                 }
3139                 *(const void **)arg = &mlx5_flow_ops;
3140                 return 0;
3141         case RTE_ETH_FILTER_FDIR:
3142                 return mlx5_fdir_ctrl_func(dev, filter_op, arg);
3143         default:
3144                 DRV_LOG(ERR, "port %u filter type (%d) not supported",
3145                         dev->data->port_id, filter_type);
3146                 rte_errno = ENOTSUP;
3147                 return -rte_errno;
3148         }
3149         return 0;
3150 }