1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016 6WIND S.A.
3 * Copyright 2016 Mellanox Technologies, Ltd
11 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
13 #pragma GCC diagnostic ignored "-Wpedantic"
15 #include <infiniband/verbs.h>
17 #pragma GCC diagnostic error "-Wpedantic"
20 #include <rte_common.h>
21 #include <rte_ether.h>
22 #include <rte_eth_ctrl.h>
23 #include <rte_ethdev_driver.h>
25 #include <rte_flow_driver.h>
26 #include <rte_malloc.h>
30 #include "mlx5_defs.h"
32 #include "mlx5_glue.h"
34 /* Flow priority for control plane flows. */
35 #define MLX5_CTRL_FLOW_PRIORITY 1
37 /* Internet Protocol versions. */
42 #ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
43 struct ibv_flow_spec_counter_action {
48 /* Dev ops structure defined in mlx5.c */
49 extern const struct eth_dev_ops mlx5_dev_ops;
50 extern const struct eth_dev_ops mlx5_dev_ops_isolate;
52 /** Structure give to the conversion functions. */
53 struct mlx5_flow_data {
54 struct rte_eth_dev *dev; /** Ethernet device. */
55 struct mlx5_flow_parse *parser; /** Parser context. */
56 struct rte_flow_error *error; /** Error context. */
60 mlx5_flow_create_eth(const struct rte_flow_item *item,
61 const void *default_mask,
62 struct mlx5_flow_data *data);
65 mlx5_flow_create_vlan(const struct rte_flow_item *item,
66 const void *default_mask,
67 struct mlx5_flow_data *data);
70 mlx5_flow_create_ipv4(const struct rte_flow_item *item,
71 const void *default_mask,
72 struct mlx5_flow_data *data);
75 mlx5_flow_create_ipv6(const struct rte_flow_item *item,
76 const void *default_mask,
77 struct mlx5_flow_data *data);
80 mlx5_flow_create_udp(const struct rte_flow_item *item,
81 const void *default_mask,
82 struct mlx5_flow_data *data);
85 mlx5_flow_create_tcp(const struct rte_flow_item *item,
86 const void *default_mask,
87 struct mlx5_flow_data *data);
90 mlx5_flow_create_vxlan(const struct rte_flow_item *item,
91 const void *default_mask,
92 struct mlx5_flow_data *data);
95 mlx5_flow_create_gre(const struct rte_flow_item *item,
96 const void *default_mask,
97 struct mlx5_flow_data *data);
99 struct mlx5_flow_parse;
102 mlx5_flow_create_copy(struct mlx5_flow_parse *parser, void *src,
106 mlx5_flow_create_flag_mark(struct mlx5_flow_parse *parser, uint32_t mark_id);
109 mlx5_flow_create_count(struct rte_eth_dev *dev, struct mlx5_flow_parse *parser);
111 /* Hash RX queue types. */
123 /* Initialization data for hash RX queue. */
124 struct hash_rxq_init {
125 uint64_t hash_fields; /* Fields that participate in the hash. */
126 uint64_t dpdk_rss_hf; /* Matching DPDK RSS hash fields. */
127 unsigned int flow_priority; /* Flow priority to use. */
128 unsigned int ip_version; /* Internet protocol. */
131 /* Initialization data for hash RX queues. */
132 const struct hash_rxq_init hash_rxq_init[] = {
134 .hash_fields = (IBV_RX_HASH_SRC_IPV4 |
135 IBV_RX_HASH_DST_IPV4 |
136 IBV_RX_HASH_SRC_PORT_TCP |
137 IBV_RX_HASH_DST_PORT_TCP),
138 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV4_TCP,
140 .ip_version = MLX5_IPV4,
143 .hash_fields = (IBV_RX_HASH_SRC_IPV4 |
144 IBV_RX_HASH_DST_IPV4 |
145 IBV_RX_HASH_SRC_PORT_UDP |
146 IBV_RX_HASH_DST_PORT_UDP),
147 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV4_UDP,
149 .ip_version = MLX5_IPV4,
152 .hash_fields = (IBV_RX_HASH_SRC_IPV4 |
153 IBV_RX_HASH_DST_IPV4),
154 .dpdk_rss_hf = (ETH_RSS_IPV4 |
157 .ip_version = MLX5_IPV4,
160 .hash_fields = (IBV_RX_HASH_SRC_IPV6 |
161 IBV_RX_HASH_DST_IPV6 |
162 IBV_RX_HASH_SRC_PORT_TCP |
163 IBV_RX_HASH_DST_PORT_TCP),
164 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV6_TCP,
166 .ip_version = MLX5_IPV6,
169 .hash_fields = (IBV_RX_HASH_SRC_IPV6 |
170 IBV_RX_HASH_DST_IPV6 |
171 IBV_RX_HASH_SRC_PORT_UDP |
172 IBV_RX_HASH_DST_PORT_UDP),
173 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV6_UDP,
175 .ip_version = MLX5_IPV6,
178 .hash_fields = (IBV_RX_HASH_SRC_IPV6 |
179 IBV_RX_HASH_DST_IPV6),
180 .dpdk_rss_hf = (ETH_RSS_IPV6 |
183 .ip_version = MLX5_IPV6,
192 /* Number of entries in hash_rxq_init[]. */
193 const unsigned int hash_rxq_init_n = RTE_DIM(hash_rxq_init);
195 /** Structure for holding counter stats. */
196 struct mlx5_flow_counter_stats {
197 uint64_t hits; /**< Number of packets matched by the rule. */
198 uint64_t bytes; /**< Number of bytes matched by the rule. */
201 /** Structure for Drop queue. */
202 struct mlx5_hrxq_drop {
203 struct ibv_rwq_ind_table *ind_table; /**< Indirection table. */
204 struct ibv_qp *qp; /**< Verbs queue pair. */
205 struct ibv_wq *wq; /**< Verbs work queue. */
206 struct ibv_cq *cq; /**< Verbs completion queue. */
209 /* Flows structures. */
211 uint64_t hash_fields; /**< Fields that participate in the hash. */
212 struct ibv_flow_attr *ibv_attr; /**< Pointer to Verbs attributes. */
213 struct ibv_flow *ibv_flow; /**< Verbs flow. */
214 struct mlx5_hrxq *hrxq; /**< Hash Rx queues. */
217 /* Drop flows structures. */
218 struct mlx5_flow_drop {
219 struct ibv_flow_attr *ibv_attr; /**< Pointer to Verbs attributes. */
220 struct ibv_flow *ibv_flow; /**< Verbs flow. */
224 TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */
225 uint32_t mark:1; /**< Set if the flow is marked. */
226 uint32_t drop:1; /**< Drop queue. */
227 struct rte_flow_action_rss rss_conf; /**< RSS configuration */
228 uint16_t (*queues)[]; /**< Queues indexes to use. */
229 uint8_t rss_key[40]; /**< copy of the RSS key. */
230 uint32_t tunnel; /**< Tunnel type of RTE_PTYPE_TUNNEL_XXX. */
231 struct ibv_counter_set *cs; /**< Holds the counters for the rule. */
232 struct mlx5_flow_counter_stats counter_stats;/**<The counter stats. */
233 struct mlx5_flow frxq[RTE_DIM(hash_rxq_init)];
234 /**< Flow with Rx queue. */
237 /** Static initializer for items. */
239 (const enum rte_flow_item_type []){ \
240 __VA_ARGS__, RTE_FLOW_ITEM_TYPE_END, \
243 #define IS_TUNNEL(type) ( \
244 (type) == RTE_FLOW_ITEM_TYPE_VXLAN || \
245 (type) == RTE_FLOW_ITEM_TYPE_GRE)
247 const uint32_t flow_ptype[] = {
248 [RTE_FLOW_ITEM_TYPE_VXLAN] = RTE_PTYPE_TUNNEL_VXLAN,
249 [RTE_FLOW_ITEM_TYPE_GRE] = RTE_PTYPE_TUNNEL_GRE,
252 #define PTYPE_IDX(t) ((RTE_PTYPE_TUNNEL_MASK & (t)) >> 12)
254 const uint32_t ptype_ext[] = {
255 [PTYPE_IDX(RTE_PTYPE_TUNNEL_VXLAN)] = RTE_PTYPE_TUNNEL_VXLAN |
257 [PTYPE_IDX(RTE_PTYPE_TUNNEL_GRE)] = RTE_PTYPE_TUNNEL_GRE,
260 /** Structure to generate a simple graph of layers supported by the NIC. */
261 struct mlx5_flow_items {
262 /** List of possible actions for these items. */
263 const enum rte_flow_action_type *const actions;
264 /** Bit-masks corresponding to the possibilities for the item. */
267 * Default bit-masks to use when item->mask is not provided. When
268 * \default_mask is also NULL, the full supported bit-mask (\mask) is
271 const void *default_mask;
272 /** Bit-masks size in bytes. */
273 const unsigned int mask_sz;
275 * Conversion function from rte_flow to NIC specific flow.
278 * rte_flow item to convert.
279 * @param default_mask
280 * Default bit-masks to use when item->mask is not provided.
282 * Internal structure to store the conversion.
285 * 0 on success, a negative errno value otherwise and rte_errno is
288 int (*convert)(const struct rte_flow_item *item,
289 const void *default_mask,
290 struct mlx5_flow_data *data);
291 /** Size in bytes of the destination structure. */
292 const unsigned int dst_sz;
293 /** List of possible following items. */
294 const enum rte_flow_item_type *const items;
297 /** Valid action for this PMD. */
298 static const enum rte_flow_action_type valid_actions[] = {
299 RTE_FLOW_ACTION_TYPE_DROP,
300 RTE_FLOW_ACTION_TYPE_QUEUE,
301 RTE_FLOW_ACTION_TYPE_MARK,
302 RTE_FLOW_ACTION_TYPE_FLAG,
303 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
304 RTE_FLOW_ACTION_TYPE_COUNT,
306 RTE_FLOW_ACTION_TYPE_END,
309 /** Graph of supported items and associated actions. */
310 static const struct mlx5_flow_items mlx5_flow_items[] = {
311 [RTE_FLOW_ITEM_TYPE_END] = {
312 .items = ITEMS(RTE_FLOW_ITEM_TYPE_ETH,
313 RTE_FLOW_ITEM_TYPE_VXLAN,
314 RTE_FLOW_ITEM_TYPE_GRE),
316 [RTE_FLOW_ITEM_TYPE_ETH] = {
317 .items = ITEMS(RTE_FLOW_ITEM_TYPE_VLAN,
318 RTE_FLOW_ITEM_TYPE_IPV4,
319 RTE_FLOW_ITEM_TYPE_IPV6),
320 .actions = valid_actions,
321 .mask = &(const struct rte_flow_item_eth){
322 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
323 .src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
326 .default_mask = &rte_flow_item_eth_mask,
327 .mask_sz = sizeof(struct rte_flow_item_eth),
328 .convert = mlx5_flow_create_eth,
329 .dst_sz = sizeof(struct ibv_flow_spec_eth),
331 [RTE_FLOW_ITEM_TYPE_VLAN] = {
332 .items = ITEMS(RTE_FLOW_ITEM_TYPE_IPV4,
333 RTE_FLOW_ITEM_TYPE_IPV6),
334 .actions = valid_actions,
335 .mask = &(const struct rte_flow_item_vlan){
339 .default_mask = &rte_flow_item_vlan_mask,
340 .mask_sz = sizeof(struct rte_flow_item_vlan),
341 .convert = mlx5_flow_create_vlan,
344 [RTE_FLOW_ITEM_TYPE_IPV4] = {
345 .items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
346 RTE_FLOW_ITEM_TYPE_TCP,
347 RTE_FLOW_ITEM_TYPE_GRE),
348 .actions = valid_actions,
349 .mask = &(const struct rte_flow_item_ipv4){
353 .type_of_service = -1,
357 .default_mask = &rte_flow_item_ipv4_mask,
358 .mask_sz = sizeof(struct rte_flow_item_ipv4),
359 .convert = mlx5_flow_create_ipv4,
360 .dst_sz = sizeof(struct ibv_flow_spec_ipv4_ext),
362 [RTE_FLOW_ITEM_TYPE_IPV6] = {
363 .items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
364 RTE_FLOW_ITEM_TYPE_TCP,
365 RTE_FLOW_ITEM_TYPE_GRE),
366 .actions = valid_actions,
367 .mask = &(const struct rte_flow_item_ipv6){
370 0xff, 0xff, 0xff, 0xff,
371 0xff, 0xff, 0xff, 0xff,
372 0xff, 0xff, 0xff, 0xff,
373 0xff, 0xff, 0xff, 0xff,
376 0xff, 0xff, 0xff, 0xff,
377 0xff, 0xff, 0xff, 0xff,
378 0xff, 0xff, 0xff, 0xff,
379 0xff, 0xff, 0xff, 0xff,
386 .default_mask = &rte_flow_item_ipv6_mask,
387 .mask_sz = sizeof(struct rte_flow_item_ipv6),
388 .convert = mlx5_flow_create_ipv6,
389 .dst_sz = sizeof(struct ibv_flow_spec_ipv6),
391 [RTE_FLOW_ITEM_TYPE_UDP] = {
392 .items = ITEMS(RTE_FLOW_ITEM_TYPE_VXLAN),
393 .actions = valid_actions,
394 .mask = &(const struct rte_flow_item_udp){
400 .default_mask = &rte_flow_item_udp_mask,
401 .mask_sz = sizeof(struct rte_flow_item_udp),
402 .convert = mlx5_flow_create_udp,
403 .dst_sz = sizeof(struct ibv_flow_spec_tcp_udp),
405 [RTE_FLOW_ITEM_TYPE_TCP] = {
406 .actions = valid_actions,
407 .mask = &(const struct rte_flow_item_tcp){
413 .default_mask = &rte_flow_item_tcp_mask,
414 .mask_sz = sizeof(struct rte_flow_item_tcp),
415 .convert = mlx5_flow_create_tcp,
416 .dst_sz = sizeof(struct ibv_flow_spec_tcp_udp),
418 [RTE_FLOW_ITEM_TYPE_GRE] = {
419 .items = ITEMS(RTE_FLOW_ITEM_TYPE_ETH,
420 RTE_FLOW_ITEM_TYPE_IPV4,
421 RTE_FLOW_ITEM_TYPE_IPV6),
422 .actions = valid_actions,
423 .mask = &(const struct rte_flow_item_gre){
426 .default_mask = &rte_flow_item_gre_mask,
427 .mask_sz = sizeof(struct rte_flow_item_gre),
428 .convert = mlx5_flow_create_gre,
429 .dst_sz = sizeof(struct ibv_flow_spec_tunnel),
431 [RTE_FLOW_ITEM_TYPE_VXLAN] = {
432 .items = ITEMS(RTE_FLOW_ITEM_TYPE_ETH,
433 RTE_FLOW_ITEM_TYPE_IPV4, /* For L3 VXLAN. */
434 RTE_FLOW_ITEM_TYPE_IPV6), /* For L3 VXLAN. */
435 .actions = valid_actions,
436 .mask = &(const struct rte_flow_item_vxlan){
437 .vni = "\xff\xff\xff",
439 .default_mask = &rte_flow_item_vxlan_mask,
440 .mask_sz = sizeof(struct rte_flow_item_vxlan),
441 .convert = mlx5_flow_create_vxlan,
442 .dst_sz = sizeof(struct ibv_flow_spec_tunnel),
446 /** Structure to pass to the conversion function. */
447 struct mlx5_flow_parse {
448 uint32_t inner; /**< Verbs value, set once tunnel is encountered. */
450 /**< Whether resources should remain after a validate. */
451 uint32_t drop:1; /**< Target is a drop queue. */
452 uint32_t mark:1; /**< Mark is present in the flow. */
453 uint32_t count:1; /**< Count is present in the flow. */
454 uint32_t mark_id; /**< Mark identifier. */
455 struct rte_flow_action_rss rss_conf; /**< RSS configuration */
456 uint16_t queues[RTE_MAX_QUEUES_PER_PORT]; /**< Queues indexes to use. */
457 uint8_t rss_key[40]; /**< copy of the RSS key. */
458 enum hash_rxq_type layer; /**< Last pattern layer detected. */
459 enum hash_rxq_type out_layer; /**< Last outer pattern layer detected. */
460 uint32_t tunnel; /**< Tunnel type of RTE_PTYPE_TUNNEL_XXX. */
461 struct ibv_counter_set *cs; /**< Holds the counter set for the rule */
463 struct ibv_flow_attr *ibv_attr;
464 /**< Pointer to Verbs attributes. */
466 /**< Current position or total size of the attribute. */
467 } queue[RTE_DIM(hash_rxq_init)];
470 static const struct rte_flow_ops mlx5_flow_ops = {
471 .validate = mlx5_flow_validate,
472 .create = mlx5_flow_create,
473 .destroy = mlx5_flow_destroy,
474 .flush = mlx5_flow_flush,
475 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
476 .query = mlx5_flow_query,
480 .isolate = mlx5_flow_isolate,
483 /* Convert FDIR request to Generic flow. */
485 struct rte_flow_attr attr;
486 struct rte_flow_action actions[2];
487 struct rte_flow_item items[4];
488 struct rte_flow_item_eth l2;
489 struct rte_flow_item_eth l2_mask;
491 struct rte_flow_item_ipv4 ipv4;
492 struct rte_flow_item_ipv6 ipv6;
495 struct rte_flow_item_ipv4 ipv4;
496 struct rte_flow_item_ipv6 ipv6;
499 struct rte_flow_item_udp udp;
500 struct rte_flow_item_tcp tcp;
503 struct rte_flow_item_udp udp;
504 struct rte_flow_item_tcp tcp;
506 struct rte_flow_action_queue queue;
509 /* Verbs specification header. */
510 struct ibv_spec_header {
511 enum ibv_flow_spec_type type;
516 * Check support for a given item.
519 * Item specification.
521 * Bit-masks covering supported fields to compare with spec, last and mask in
524 * Bit-Mask size in bytes.
527 * 0 on success, a negative errno value otherwise and rte_errno is set.
530 mlx5_flow_item_validate(const struct rte_flow_item *item,
531 const uint8_t *mask, unsigned int size)
533 if (!item->spec && (item->mask || item->last)) {
537 if (item->spec && !item->mask) {
539 const uint8_t *spec = item->spec;
541 for (i = 0; i < size; ++i)
542 if ((spec[i] | mask[i]) != mask[i]) {
547 if (item->last && !item->mask) {
549 const uint8_t *spec = item->last;
551 for (i = 0; i < size; ++i)
552 if ((spec[i] | mask[i]) != mask[i]) {
559 const uint8_t *spec = item->spec;
561 for (i = 0; i < size; ++i)
562 if ((spec[i] | mask[i]) != mask[i]) {
567 if (item->spec && item->last) {
570 const uint8_t *apply = mask;
576 for (i = 0; i < size; ++i) {
577 spec[i] = ((const uint8_t *)item->spec)[i] & apply[i];
578 last[i] = ((const uint8_t *)item->last)[i] & apply[i];
580 ret = memcmp(spec, last, size);
590 * Extract attribute to the parser.
593 * Flow rule attributes.
595 * Perform verbose error reporting if not NULL.
598 * 0 on success, a negative errno value otherwise and rte_errno is set.
601 mlx5_flow_convert_attributes(const struct rte_flow_attr *attr,
602 struct rte_flow_error *error)
605 rte_flow_error_set(error, ENOTSUP,
606 RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
608 "groups are not supported");
611 if (attr->priority && attr->priority != MLX5_CTRL_FLOW_PRIORITY) {
612 rte_flow_error_set(error, ENOTSUP,
613 RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
615 "priorities are not supported");
619 rte_flow_error_set(error, ENOTSUP,
620 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
622 "egress is not supported");
625 if (attr->transfer) {
626 rte_flow_error_set(error, ENOTSUP,
627 RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
629 "transfer is not supported");
632 if (!attr->ingress) {
633 rte_flow_error_set(error, ENOTSUP,
634 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
636 "only ingress is supported");
643 * Extract actions request to the parser.
646 * Pointer to Ethernet device.
648 * Associated actions (list terminated by the END action).
650 * Perform verbose error reporting if not NULL.
651 * @param[in, out] parser
652 * Internal parser structure.
655 * 0 on success, a negative errno value otherwise and rte_errno is set.
658 mlx5_flow_convert_actions(struct rte_eth_dev *dev,
659 const struct rte_flow_action actions[],
660 struct rte_flow_error *error,
661 struct mlx5_flow_parse *parser)
663 enum { FATE = 1, MARK = 2, COUNT = 4, };
664 uint32_t overlap = 0;
665 struct priv *priv = dev->data->dev_private;
667 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
668 if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) {
670 } else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
672 goto exit_action_overlap;
675 } else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
676 const struct rte_flow_action_queue *queue =
677 (const struct rte_flow_action_queue *)
681 goto exit_action_overlap;
683 if (!queue || (queue->index > (priv->rxqs_n - 1)))
684 goto exit_action_not_supported;
685 parser->queues[0] = queue->index;
686 parser->rss_conf = (struct rte_flow_action_rss){
688 .queue = parser->queues,
690 } else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
691 const struct rte_flow_action_rss *rss =
692 (const struct rte_flow_action_rss *)
694 const uint8_t *rss_key;
695 uint32_t rss_key_len;
699 goto exit_action_overlap;
702 rss->func != RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
703 rte_flow_error_set(error, EINVAL,
704 RTE_FLOW_ERROR_TYPE_ACTION,
706 "the only supported RSS hash"
707 " function is Toeplitz");
711 rte_flow_error_set(error, EINVAL,
712 RTE_FLOW_ERROR_TYPE_ACTION,
714 "a nonzero RSS encapsulation"
715 " level is not supported");
718 if (rss->types & MLX5_RSS_HF_MASK) {
719 rte_flow_error_set(error, EINVAL,
720 RTE_FLOW_ERROR_TYPE_ACTION,
722 "unsupported RSS type"
727 rss_key_len = rss->key_len;
730 rss_key_len = rss_hash_default_key_len;
731 rss_key = rss_hash_default_key;
733 if (rss_key_len != RTE_DIM(parser->rss_key)) {
734 rte_flow_error_set(error, EINVAL,
735 RTE_FLOW_ERROR_TYPE_ACTION,
737 "RSS hash key must be"
738 " exactly 40 bytes long");
741 if (!rss->queue_num) {
742 rte_flow_error_set(error, EINVAL,
743 RTE_FLOW_ERROR_TYPE_ACTION,
748 if (rss->queue_num > RTE_DIM(parser->queues)) {
749 rte_flow_error_set(error, EINVAL,
750 RTE_FLOW_ERROR_TYPE_ACTION,
752 "too many queues for RSS"
756 for (n = 0; n < rss->queue_num; ++n) {
757 if (rss->queue[n] >= priv->rxqs_n) {
758 rte_flow_error_set(error, EINVAL,
759 RTE_FLOW_ERROR_TYPE_ACTION,
761 "queue id > number of"
766 parser->rss_conf = (struct rte_flow_action_rss){
767 .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
770 .key_len = rss_key_len,
771 .queue_num = rss->queue_num,
772 .key = memcpy(parser->rss_key, rss_key,
773 sizeof(*rss_key) * rss_key_len),
774 .queue = memcpy(parser->queues, rss->queue,
775 sizeof(*rss->queue) *
778 } else if (actions->type == RTE_FLOW_ACTION_TYPE_MARK) {
779 const struct rte_flow_action_mark *mark =
780 (const struct rte_flow_action_mark *)
784 goto exit_action_overlap;
787 rte_flow_error_set(error, EINVAL,
788 RTE_FLOW_ERROR_TYPE_ACTION,
790 "mark must be defined");
792 } else if (mark->id >= MLX5_FLOW_MARK_MAX) {
793 rte_flow_error_set(error, ENOTSUP,
794 RTE_FLOW_ERROR_TYPE_ACTION,
796 "mark must be between 0"
801 parser->mark_id = mark->id;
802 } else if (actions->type == RTE_FLOW_ACTION_TYPE_FLAG) {
804 goto exit_action_overlap;
807 } else if (actions->type == RTE_FLOW_ACTION_TYPE_COUNT &&
808 priv->config.flow_counter_en) {
810 goto exit_action_overlap;
814 goto exit_action_not_supported;
817 /* When fate is unknown, drop traffic. */
818 if (!(overlap & FATE))
820 if (parser->drop && parser->mark)
822 if (!parser->rss_conf.queue_num && !parser->drop) {
823 rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
824 NULL, "no valid action");
828 exit_action_not_supported:
829 rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
830 actions, "action not supported");
833 rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
834 actions, "overlapping actions are not supported");
842 * Pattern specification (list terminated by the END pattern item).
844 * Perform verbose error reporting if not NULL.
845 * @param[in, out] parser
846 * Internal parser structure.
849 * 0 on success, a negative errno value otherwise and rte_errno is set.
852 mlx5_flow_convert_items_validate(const struct rte_flow_item items[],
853 struct rte_flow_error *error,
854 struct mlx5_flow_parse *parser)
856 const struct mlx5_flow_items *cur_item = mlx5_flow_items;
860 /* Initialise the offsets to start after verbs attribute. */
861 for (i = 0; i != hash_rxq_init_n; ++i)
862 parser->queue[i].offset = sizeof(struct ibv_flow_attr);
863 for (; items->type != RTE_FLOW_ITEM_TYPE_END; ++items) {
864 const struct mlx5_flow_items *token = NULL;
867 if (items->type == RTE_FLOW_ITEM_TYPE_VOID)
871 cur_item->items[i] != RTE_FLOW_ITEM_TYPE_END;
873 if (cur_item->items[i] == items->type) {
874 token = &mlx5_flow_items[items->type];
880 goto exit_item_not_supported;
883 ret = mlx5_flow_item_validate(items,
884 (const uint8_t *)cur_item->mask,
887 goto exit_item_not_supported;
888 if (IS_TUNNEL(items->type)) {
889 if (parser->tunnel) {
890 rte_flow_error_set(error, ENOTSUP,
891 RTE_FLOW_ERROR_TYPE_ITEM,
893 "Cannot recognize multiple"
894 " tunnel encapsulations.");
897 parser->inner = IBV_FLOW_SPEC_INNER;
898 parser->tunnel = flow_ptype[items->type];
901 parser->queue[HASH_RXQ_ETH].offset += cur_item->dst_sz;
903 for (n = 0; n != hash_rxq_init_n; ++n)
904 parser->queue[n].offset += cur_item->dst_sz;
908 parser->queue[HASH_RXQ_ETH].offset +=
909 sizeof(struct ibv_flow_spec_action_drop);
912 for (i = 0; i != hash_rxq_init_n; ++i)
913 parser->queue[i].offset +=
914 sizeof(struct ibv_flow_spec_action_tag);
917 unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
919 for (i = 0; i != hash_rxq_init_n; ++i)
920 parser->queue[i].offset += size;
923 exit_item_not_supported:
924 return rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_ITEM,
925 items, "item not supported");
929 * Allocate memory space to store verbs flow attributes.
932 * Amount of byte to allocate.
934 * Perform verbose error reporting if not NULL.
937 * A verbs flow attribute on success, NULL otherwise and rte_errno is set.
939 static struct ibv_flow_attr *
940 mlx5_flow_convert_allocate(unsigned int size, struct rte_flow_error *error)
942 struct ibv_flow_attr *ibv_attr;
944 ibv_attr = rte_calloc(__func__, 1, size, 0);
946 rte_flow_error_set(error, ENOMEM,
947 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
949 "cannot allocate verbs spec attributes");
956 * Make inner packet matching with an higher priority from the non Inner
960 * Pointer to Ethernet device.
961 * @param[in, out] parser
962 * Internal parser structure.
964 * User flow attribute.
967 mlx5_flow_update_priority(struct rte_eth_dev *dev,
968 struct mlx5_flow_parse *parser,
969 const struct rte_flow_attr *attr)
971 struct priv *priv = dev->data->dev_private;
975 /* 8 priorities >= 16 priorities
976 * Control flow: 4-7 8-15
977 * User normal flow: 1-3 4-7
978 * User tunnel flow: 0-2 0-3
980 priority = attr->priority * MLX5_VERBS_FLOW_PRIO_8;
981 if (priv->config.max_verbs_prio == MLX5_VERBS_FLOW_PRIO_8)
984 * Lower non-tunnel flow Verbs priority 1 if only support 8 Verbs
985 * priorities, lower 4 otherwise.
987 if (!parser->inner) {
988 if (priv->config.max_verbs_prio == MLX5_VERBS_FLOW_PRIO_8)
991 priority += MLX5_VERBS_FLOW_PRIO_8 / 2;
994 parser->queue[HASH_RXQ_ETH].ibv_attr->priority = priority +
995 hash_rxq_init[HASH_RXQ_ETH].flow_priority;
998 for (i = 0; i != hash_rxq_init_n; ++i) {
999 if (!parser->queue[i].ibv_attr)
1001 parser->queue[i].ibv_attr->priority = priority +
1002 hash_rxq_init[i].flow_priority;
1007 * Finalise verbs flow attributes.
1009 * @param[in, out] parser
1010 * Internal parser structure.
1013 mlx5_flow_convert_finalise(struct mlx5_flow_parse *parser)
1015 const unsigned int ipv4 =
1016 hash_rxq_init[parser->layer].ip_version == MLX5_IPV4;
1017 const enum hash_rxq_type hmin = ipv4 ? HASH_RXQ_TCPV4 : HASH_RXQ_TCPV6;
1018 const enum hash_rxq_type hmax = ipv4 ? HASH_RXQ_IPV4 : HASH_RXQ_IPV6;
1019 const enum hash_rxq_type ohmin = ipv4 ? HASH_RXQ_TCPV6 : HASH_RXQ_TCPV4;
1020 const enum hash_rxq_type ohmax = ipv4 ? HASH_RXQ_IPV6 : HASH_RXQ_IPV4;
1021 const enum hash_rxq_type ip = ipv4 ? HASH_RXQ_IPV4 : HASH_RXQ_IPV6;
1024 /* Remove any other flow not matching the pattern. */
1025 if (parser->rss_conf.queue_num == 1 && !parser->rss_conf.types) {
1026 for (i = 0; i != hash_rxq_init_n; ++i) {
1027 if (i == HASH_RXQ_ETH)
1029 rte_free(parser->queue[i].ibv_attr);
1030 parser->queue[i].ibv_attr = NULL;
1034 if (parser->layer == HASH_RXQ_ETH) {
1038 * This layer becomes useless as the pattern define under
1041 rte_free(parser->queue[HASH_RXQ_ETH].ibv_attr);
1042 parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
1044 /* Remove opposite kind of layer e.g. IPv6 if the pattern is IPv4. */
1045 for (i = ohmin; i != (ohmax + 1); ++i) {
1046 if (!parser->queue[i].ibv_attr)
1048 rte_free(parser->queue[i].ibv_attr);
1049 parser->queue[i].ibv_attr = NULL;
1051 /* Remove impossible flow according to the RSS configuration. */
1052 if (hash_rxq_init[parser->layer].dpdk_rss_hf &
1053 parser->rss_conf.types) {
1054 /* Remove any other flow. */
1055 for (i = hmin; i != (hmax + 1); ++i) {
1056 if ((i == parser->layer) ||
1057 (!parser->queue[i].ibv_attr))
1059 rte_free(parser->queue[i].ibv_attr);
1060 parser->queue[i].ibv_attr = NULL;
1062 } else if (!parser->queue[ip].ibv_attr) {
1063 /* no RSS possible with the current configuration. */
1064 parser->rss_conf.queue_num = 1;
1069 * Fill missing layers in verbs specifications, or compute the correct
1070 * offset to allocate the memory space for the attributes and
1073 for (i = 0; i != hash_rxq_init_n - 1; ++i) {
1075 struct ibv_flow_spec_ipv4_ext ipv4;
1076 struct ibv_flow_spec_ipv6 ipv6;
1077 struct ibv_flow_spec_tcp_udp udp_tcp;
1082 if (i == parser->layer)
1084 if (parser->layer == HASH_RXQ_ETH) {
1085 if (hash_rxq_init[i].ip_version == MLX5_IPV4) {
1086 size = sizeof(struct ibv_flow_spec_ipv4_ext);
1087 specs.ipv4 = (struct ibv_flow_spec_ipv4_ext){
1088 .type = IBV_FLOW_SPEC_IPV4_EXT,
1092 size = sizeof(struct ibv_flow_spec_ipv6);
1093 specs.ipv6 = (struct ibv_flow_spec_ipv6){
1094 .type = IBV_FLOW_SPEC_IPV6,
1098 if (parser->queue[i].ibv_attr) {
1099 dst = (void *)((uintptr_t)
1100 parser->queue[i].ibv_attr +
1101 parser->queue[i].offset);
1102 memcpy(dst, &specs, size);
1103 ++parser->queue[i].ibv_attr->num_of_specs;
1105 parser->queue[i].offset += size;
1107 if ((i == HASH_RXQ_UDPV4) || (i == HASH_RXQ_TCPV4) ||
1108 (i == HASH_RXQ_UDPV6) || (i == HASH_RXQ_TCPV6)) {
1109 size = sizeof(struct ibv_flow_spec_tcp_udp);
1110 specs.udp_tcp = (struct ibv_flow_spec_tcp_udp) {
1111 .type = ((i == HASH_RXQ_UDPV4 ||
1112 i == HASH_RXQ_UDPV6) ?
1117 if (parser->queue[i].ibv_attr) {
1118 dst = (void *)((uintptr_t)
1119 parser->queue[i].ibv_attr +
1120 parser->queue[i].offset);
1121 memcpy(dst, &specs, size);
1122 ++parser->queue[i].ibv_attr->num_of_specs;
1124 parser->queue[i].offset += size;
1130 * Validate and convert a flow supported by the NIC.
1133 * Pointer to Ethernet device.
1135 * Flow rule attributes.
1136 * @param[in] pattern
1137 * Pattern specification (list terminated by the END pattern item).
1138 * @param[in] actions
1139 * Associated actions (list terminated by the END action).
1141 * Perform verbose error reporting if not NULL.
1142 * @param[in, out] parser
1143 * Internal parser structure.
1146 * 0 on success, a negative errno value otherwise and rte_errno is set.
1149 mlx5_flow_convert(struct rte_eth_dev *dev,
1150 const struct rte_flow_attr *attr,
1151 const struct rte_flow_item items[],
1152 const struct rte_flow_action actions[],
1153 struct rte_flow_error *error,
1154 struct mlx5_flow_parse *parser)
1156 const struct mlx5_flow_items *cur_item = mlx5_flow_items;
1160 /* First step. Validate the attributes, items and actions. */
1161 *parser = (struct mlx5_flow_parse){
1162 .create = parser->create,
1163 .layer = HASH_RXQ_ETH,
1164 .mark_id = MLX5_FLOW_MARK_DEFAULT,
1166 ret = mlx5_flow_convert_attributes(attr, error);
1169 ret = mlx5_flow_convert_actions(dev, actions, error, parser);
1172 ret = mlx5_flow_convert_items_validate(items, error, parser);
1175 mlx5_flow_convert_finalise(parser);
1178 * Allocate the memory space to store verbs specifications.
1181 unsigned int offset = parser->queue[HASH_RXQ_ETH].offset;
1183 parser->queue[HASH_RXQ_ETH].ibv_attr =
1184 mlx5_flow_convert_allocate(offset, error);
1185 if (!parser->queue[HASH_RXQ_ETH].ibv_attr)
1187 parser->queue[HASH_RXQ_ETH].offset =
1188 sizeof(struct ibv_flow_attr);
1190 for (i = 0; i != hash_rxq_init_n; ++i) {
1191 unsigned int offset;
1193 if (!(parser->rss_conf.types &
1194 hash_rxq_init[i].dpdk_rss_hf) &&
1195 (i != HASH_RXQ_ETH))
1197 offset = parser->queue[i].offset;
1198 parser->queue[i].ibv_attr =
1199 mlx5_flow_convert_allocate(offset, error);
1200 if (!parser->queue[i].ibv_attr)
1202 parser->queue[i].offset = sizeof(struct ibv_flow_attr);
1205 /* Third step. Conversion parse, fill the specifications. */
1208 for (; items->type != RTE_FLOW_ITEM_TYPE_END; ++items) {
1209 struct mlx5_flow_data data = {
1215 if (items->type == RTE_FLOW_ITEM_TYPE_VOID)
1217 cur_item = &mlx5_flow_items[items->type];
1218 ret = cur_item->convert(items,
1219 (cur_item->default_mask ?
1220 cur_item->default_mask :
1227 mlx5_flow_create_flag_mark(parser, parser->mark_id);
1228 if (parser->count && parser->create) {
1229 mlx5_flow_create_count(dev, parser);
1231 goto exit_count_error;
1234 * Last step. Complete missing specification to reach the RSS
1238 mlx5_flow_convert_finalise(parser);
1239 mlx5_flow_update_priority(dev, parser, attr);
1241 /* Only verification is expected, all resources should be released. */
1242 if (!parser->create) {
1243 for (i = 0; i != hash_rxq_init_n; ++i) {
1244 if (parser->queue[i].ibv_attr) {
1245 rte_free(parser->queue[i].ibv_attr);
1246 parser->queue[i].ibv_attr = NULL;
1252 for (i = 0; i != hash_rxq_init_n; ++i) {
1253 if (parser->queue[i].ibv_attr) {
1254 rte_free(parser->queue[i].ibv_attr);
1255 parser->queue[i].ibv_attr = NULL;
1258 rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1259 NULL, "cannot allocate verbs spec attributes");
1262 rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1263 NULL, "cannot create counter");
1268 * Copy the specification created into the flow.
1271 * Internal parser structure.
1273 * Create specification.
1275 * Size in bytes of the specification to copy.
1278 mlx5_flow_create_copy(struct mlx5_flow_parse *parser, void *src,
1284 for (i = 0; i != hash_rxq_init_n; ++i) {
1285 if (!parser->queue[i].ibv_attr)
1287 /* Specification must be the same l3 type or none. */
1288 if (parser->layer == HASH_RXQ_ETH ||
1289 (hash_rxq_init[parser->layer].ip_version ==
1290 hash_rxq_init[i].ip_version) ||
1291 (hash_rxq_init[i].ip_version == 0)) {
1292 dst = (void *)((uintptr_t)parser->queue[i].ibv_attr +
1293 parser->queue[i].offset);
1294 memcpy(dst, src, size);
1295 ++parser->queue[i].ibv_attr->num_of_specs;
1296 parser->queue[i].offset += size;
1302 * Convert Ethernet item to Verbs specification.
1305 * Item specification.
1306 * @param default_mask[in]
1307 * Default bit-masks to use when item->mask is not provided.
1308 * @param data[in, out]
1312 * 0 on success, a negative errno value otherwise and rte_errno is set.
1315 mlx5_flow_create_eth(const struct rte_flow_item *item,
1316 const void *default_mask,
1317 struct mlx5_flow_data *data)
1319 const struct rte_flow_item_eth *spec = item->spec;
1320 const struct rte_flow_item_eth *mask = item->mask;
1321 struct mlx5_flow_parse *parser = data->parser;
1322 const unsigned int eth_size = sizeof(struct ibv_flow_spec_eth);
1323 struct ibv_flow_spec_eth eth = {
1324 .type = parser->inner | IBV_FLOW_SPEC_ETH,
1328 /* Don't update layer for the inner pattern. */
1330 parser->layer = HASH_RXQ_ETH;
1335 mask = default_mask;
1336 memcpy(ð.val.dst_mac, spec->dst.addr_bytes, ETHER_ADDR_LEN);
1337 memcpy(ð.val.src_mac, spec->src.addr_bytes, ETHER_ADDR_LEN);
1338 eth.val.ether_type = spec->type;
1339 memcpy(ð.mask.dst_mac, mask->dst.addr_bytes, ETHER_ADDR_LEN);
1340 memcpy(ð.mask.src_mac, mask->src.addr_bytes, ETHER_ADDR_LEN);
1341 eth.mask.ether_type = mask->type;
1342 /* Remove unwanted bits from values. */
1343 for (i = 0; i < ETHER_ADDR_LEN; ++i) {
1344 eth.val.dst_mac[i] &= eth.mask.dst_mac[i];
1345 eth.val.src_mac[i] &= eth.mask.src_mac[i];
1347 eth.val.ether_type &= eth.mask.ether_type;
1349 mlx5_flow_create_copy(parser, ð, eth_size);
1354 * Convert VLAN item to Verbs specification.
1357 * Item specification.
1358 * @param default_mask[in]
1359 * Default bit-masks to use when item->mask is not provided.
1360 * @param data[in, out]
1364 * 0 on success, a negative errno value otherwise and rte_errno is set.
1367 mlx5_flow_create_vlan(const struct rte_flow_item *item,
1368 const void *default_mask,
1369 struct mlx5_flow_data *data)
1371 const struct rte_flow_item_vlan *spec = item->spec;
1372 const struct rte_flow_item_vlan *mask = item->mask;
1373 struct mlx5_flow_parse *parser = data->parser;
1374 struct ibv_flow_spec_eth *eth;
1375 const unsigned int eth_size = sizeof(struct ibv_flow_spec_eth);
1376 const char *msg = "VLAN cannot be empty";
1381 mask = default_mask;
1383 for (i = 0; i != hash_rxq_init_n; ++i) {
1384 if (!parser->queue[i].ibv_attr)
1387 eth = (void *)((uintptr_t)parser->queue[i].ibv_attr +
1388 parser->queue[i].offset - eth_size);
1389 eth->val.vlan_tag = spec->tci;
1390 eth->mask.vlan_tag = mask->tci;
1391 eth->val.vlan_tag &= eth->mask.vlan_tag;
1393 * From verbs perspective an empty VLAN is equivalent
1394 * to a packet without VLAN layer.
1396 if (!eth->mask.vlan_tag)
1398 /* Outer TPID cannot be matched. */
1399 if (eth->mask.ether_type) {
1400 msg = "VLAN TPID matching is not supported";
1403 eth->val.ether_type = spec->inner_type;
1404 eth->mask.ether_type = mask->inner_type;
1405 eth->val.ether_type &= eth->mask.ether_type;
1410 return rte_flow_error_set(data->error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
1415 * Convert IPv4 item to Verbs specification.
1418 * Item specification.
1419 * @param default_mask[in]
1420 * Default bit-masks to use when item->mask is not provided.
1421 * @param data[in, out]
1425 * 0 on success, a negative errno value otherwise and rte_errno is set.
1428 mlx5_flow_create_ipv4(const struct rte_flow_item *item,
1429 const void *default_mask,
1430 struct mlx5_flow_data *data)
1432 struct priv *priv = data->dev->data->dev_private;
1433 const struct rte_flow_item_ipv4 *spec = item->spec;
1434 const struct rte_flow_item_ipv4 *mask = item->mask;
1435 struct mlx5_flow_parse *parser = data->parser;
1436 unsigned int ipv4_size = sizeof(struct ibv_flow_spec_ipv4_ext);
1437 struct ibv_flow_spec_ipv4_ext ipv4 = {
1438 .type = parser->inner | IBV_FLOW_SPEC_IPV4_EXT,
1442 if (parser->layer == HASH_RXQ_TUNNEL &&
1443 parser->tunnel == ptype_ext[PTYPE_IDX(RTE_PTYPE_TUNNEL_VXLAN)] &&
1444 !priv->config.l3_vxlan_en)
1445 return rte_flow_error_set(data->error, EINVAL,
1446 RTE_FLOW_ERROR_TYPE_ITEM,
1448 "L3 VXLAN not enabled by device"
1449 " parameter and/or not configured"
1451 /* Don't update layer for the inner pattern. */
1453 parser->layer = HASH_RXQ_IPV4;
1456 mask = default_mask;
1457 ipv4.val = (struct ibv_flow_ipv4_ext_filter){
1458 .src_ip = spec->hdr.src_addr,
1459 .dst_ip = spec->hdr.dst_addr,
1460 .proto = spec->hdr.next_proto_id,
1461 .tos = spec->hdr.type_of_service,
1463 ipv4.mask = (struct ibv_flow_ipv4_ext_filter){
1464 .src_ip = mask->hdr.src_addr,
1465 .dst_ip = mask->hdr.dst_addr,
1466 .proto = mask->hdr.next_proto_id,
1467 .tos = mask->hdr.type_of_service,
1469 /* Remove unwanted bits from values. */
1470 ipv4.val.src_ip &= ipv4.mask.src_ip;
1471 ipv4.val.dst_ip &= ipv4.mask.dst_ip;
1472 ipv4.val.proto &= ipv4.mask.proto;
1473 ipv4.val.tos &= ipv4.mask.tos;
1475 mlx5_flow_create_copy(parser, &ipv4, ipv4_size);
1480 * Convert IPv6 item to Verbs specification.
1483 * Item specification.
1484 * @param default_mask[in]
1485 * Default bit-masks to use when item->mask is not provided.
1486 * @param data[in, out]
1490 * 0 on success, a negative errno value otherwise and rte_errno is set.
1493 mlx5_flow_create_ipv6(const struct rte_flow_item *item,
1494 const void *default_mask,
1495 struct mlx5_flow_data *data)
1497 struct priv *priv = data->dev->data->dev_private;
1498 const struct rte_flow_item_ipv6 *spec = item->spec;
1499 const struct rte_flow_item_ipv6 *mask = item->mask;
1500 struct mlx5_flow_parse *parser = data->parser;
1501 unsigned int ipv6_size = sizeof(struct ibv_flow_spec_ipv6);
1502 struct ibv_flow_spec_ipv6 ipv6 = {
1503 .type = parser->inner | IBV_FLOW_SPEC_IPV6,
1507 if (parser->layer == HASH_RXQ_TUNNEL &&
1508 parser->tunnel == ptype_ext[PTYPE_IDX(RTE_PTYPE_TUNNEL_VXLAN)] &&
1509 !priv->config.l3_vxlan_en)
1510 return rte_flow_error_set(data->error, EINVAL,
1511 RTE_FLOW_ERROR_TYPE_ITEM,
1513 "L3 VXLAN not enabled by device"
1514 " parameter and/or not configured"
1516 /* Don't update layer for the inner pattern. */
1518 parser->layer = HASH_RXQ_IPV6;
1521 uint32_t vtc_flow_val;
1522 uint32_t vtc_flow_mask;
1525 mask = default_mask;
1526 memcpy(&ipv6.val.src_ip, spec->hdr.src_addr,
1527 RTE_DIM(ipv6.val.src_ip));
1528 memcpy(&ipv6.val.dst_ip, spec->hdr.dst_addr,
1529 RTE_DIM(ipv6.val.dst_ip));
1530 memcpy(&ipv6.mask.src_ip, mask->hdr.src_addr,
1531 RTE_DIM(ipv6.mask.src_ip));
1532 memcpy(&ipv6.mask.dst_ip, mask->hdr.dst_addr,
1533 RTE_DIM(ipv6.mask.dst_ip));
1534 vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);
1535 vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);
1536 ipv6.val.flow_label =
1537 rte_cpu_to_be_32((vtc_flow_val & IPV6_HDR_FL_MASK) >>
1539 ipv6.val.traffic_class = (vtc_flow_val & IPV6_HDR_TC_MASK) >>
1541 ipv6.val.next_hdr = spec->hdr.proto;
1542 ipv6.val.hop_limit = spec->hdr.hop_limits;
1543 ipv6.mask.flow_label =
1544 rte_cpu_to_be_32((vtc_flow_mask & IPV6_HDR_FL_MASK) >>
1546 ipv6.mask.traffic_class = (vtc_flow_mask & IPV6_HDR_TC_MASK) >>
1548 ipv6.mask.next_hdr = mask->hdr.proto;
1549 ipv6.mask.hop_limit = mask->hdr.hop_limits;
1550 /* Remove unwanted bits from values. */
1551 for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {
1552 ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];
1553 ipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];
1555 ipv6.val.flow_label &= ipv6.mask.flow_label;
1556 ipv6.val.traffic_class &= ipv6.mask.traffic_class;
1557 ipv6.val.next_hdr &= ipv6.mask.next_hdr;
1558 ipv6.val.hop_limit &= ipv6.mask.hop_limit;
1560 mlx5_flow_create_copy(parser, &ipv6, ipv6_size);
1565 * Convert UDP item to Verbs specification.
1568 * Item specification.
1569 * @param default_mask[in]
1570 * Default bit-masks to use when item->mask is not provided.
1571 * @param data[in, out]
1575 * 0 on success, a negative errno value otherwise and rte_errno is set.
1578 mlx5_flow_create_udp(const struct rte_flow_item *item,
1579 const void *default_mask,
1580 struct mlx5_flow_data *data)
1582 const struct rte_flow_item_udp *spec = item->spec;
1583 const struct rte_flow_item_udp *mask = item->mask;
1584 struct mlx5_flow_parse *parser = data->parser;
1585 unsigned int udp_size = sizeof(struct ibv_flow_spec_tcp_udp);
1586 struct ibv_flow_spec_tcp_udp udp = {
1587 .type = parser->inner | IBV_FLOW_SPEC_UDP,
1591 /* Don't update layer for the inner pattern. */
1592 if (!parser->inner) {
1593 if (parser->layer == HASH_RXQ_IPV4)
1594 parser->layer = HASH_RXQ_UDPV4;
1596 parser->layer = HASH_RXQ_UDPV6;
1600 mask = default_mask;
1601 udp.val.dst_port = spec->hdr.dst_port;
1602 udp.val.src_port = spec->hdr.src_port;
1603 udp.mask.dst_port = mask->hdr.dst_port;
1604 udp.mask.src_port = mask->hdr.src_port;
1605 /* Remove unwanted bits from values. */
1606 udp.val.src_port &= udp.mask.src_port;
1607 udp.val.dst_port &= udp.mask.dst_port;
1609 mlx5_flow_create_copy(parser, &udp, udp_size);
1614 * Convert TCP item to Verbs specification.
1617 * Item specification.
1618 * @param default_mask[in]
1619 * Default bit-masks to use when item->mask is not provided.
1620 * @param data[in, out]
1624 * 0 on success, a negative errno value otherwise and rte_errno is set.
1627 mlx5_flow_create_tcp(const struct rte_flow_item *item,
1628 const void *default_mask,
1629 struct mlx5_flow_data *data)
1631 const struct rte_flow_item_tcp *spec = item->spec;
1632 const struct rte_flow_item_tcp *mask = item->mask;
1633 struct mlx5_flow_parse *parser = data->parser;
1634 unsigned int tcp_size = sizeof(struct ibv_flow_spec_tcp_udp);
1635 struct ibv_flow_spec_tcp_udp tcp = {
1636 .type = parser->inner | IBV_FLOW_SPEC_TCP,
1640 /* Don't update layer for the inner pattern. */
1641 if (!parser->inner) {
1642 if (parser->layer == HASH_RXQ_IPV4)
1643 parser->layer = HASH_RXQ_TCPV4;
1645 parser->layer = HASH_RXQ_TCPV6;
1649 mask = default_mask;
1650 tcp.val.dst_port = spec->hdr.dst_port;
1651 tcp.val.src_port = spec->hdr.src_port;
1652 tcp.mask.dst_port = mask->hdr.dst_port;
1653 tcp.mask.src_port = mask->hdr.src_port;
1654 /* Remove unwanted bits from values. */
1655 tcp.val.src_port &= tcp.mask.src_port;
1656 tcp.val.dst_port &= tcp.mask.dst_port;
1658 mlx5_flow_create_copy(parser, &tcp, tcp_size);
1663 * Convert VXLAN item to Verbs specification.
1666 * Item specification.
1667 * @param default_mask[in]
1668 * Default bit-masks to use when item->mask is not provided.
1669 * @param data[in, out]
1673 * 0 on success, a negative errno value otherwise and rte_errno is set.
1676 mlx5_flow_create_vxlan(const struct rte_flow_item *item,
1677 const void *default_mask,
1678 struct mlx5_flow_data *data)
1680 const struct rte_flow_item_vxlan *spec = item->spec;
1681 const struct rte_flow_item_vxlan *mask = item->mask;
1682 struct mlx5_flow_parse *parser = data->parser;
1683 unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
1684 struct ibv_flow_spec_tunnel vxlan = {
1685 .type = parser->inner | IBV_FLOW_SPEC_VXLAN_TUNNEL,
1694 parser->inner = IBV_FLOW_SPEC_INNER;
1695 parser->tunnel = ptype_ext[PTYPE_IDX(RTE_PTYPE_TUNNEL_VXLAN)];
1698 mask = default_mask;
1699 memcpy(&id.vni[1], spec->vni, 3);
1700 vxlan.val.tunnel_id = id.vlan_id;
1701 memcpy(&id.vni[1], mask->vni, 3);
1702 vxlan.mask.tunnel_id = id.vlan_id;
1703 /* Remove unwanted bits from values. */
1704 vxlan.val.tunnel_id &= vxlan.mask.tunnel_id;
1707 * Tunnel id 0 is equivalent as not adding a VXLAN layer, if only this
1708 * layer is defined in the Verbs specification it is interpreted as
1709 * wildcard and all packets will match this rule, if it follows a full
1710 * stack layer (ex: eth / ipv4 / udp), all packets matching the layers
1711 * before will also match this rule.
1712 * To avoid such situation, VNI 0 is currently refused.
1714 if (!vxlan.val.tunnel_id)
1715 return rte_flow_error_set(data->error, EINVAL,
1716 RTE_FLOW_ERROR_TYPE_ITEM,
1718 "VxLAN vni cannot be 0");
1719 mlx5_flow_create_copy(parser, &vxlan, size);
1724 * Convert GRE item to Verbs specification.
1727 * Item specification.
1728 * @param default_mask[in]
1729 * Default bit-masks to use when item->mask is not provided.
1730 * @param data[in, out]
1734 * 0 on success, a negative errno value otherwise and rte_errno is set.
1737 mlx5_flow_create_gre(const struct rte_flow_item *item __rte_unused,
1738 const void *default_mask __rte_unused,
1739 struct mlx5_flow_data *data)
1741 struct mlx5_flow_parse *parser = data->parser;
1742 unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
1743 struct ibv_flow_spec_tunnel tunnel = {
1744 .type = parser->inner | IBV_FLOW_SPEC_VXLAN_TUNNEL,
1747 struct ibv_flow_spec_ipv4_ext *ipv4;
1748 struct ibv_flow_spec_ipv6 *ipv6;
1751 parser->inner = IBV_FLOW_SPEC_INNER;
1752 parser->tunnel = ptype_ext[PTYPE_IDX(RTE_PTYPE_TUNNEL_GRE)];
1753 /* Update encapsulation IP layer protocol. */
1754 for (i = 0; i != hash_rxq_init_n; ++i) {
1755 if (!parser->queue[i].ibv_attr)
1757 if (parser->out_layer == HASH_RXQ_IPV4) {
1758 ipv4 = (void *)((uintptr_t)parser->queue[i].ibv_attr +
1759 parser->queue[i].offset -
1760 sizeof(struct ibv_flow_spec_ipv4_ext));
1761 if (ipv4->mask.proto && ipv4->val.proto != MLX5_GRE)
1763 ipv4->val.proto = MLX5_GRE;
1764 ipv4->mask.proto = 0xff;
1765 } else if (parser->out_layer == HASH_RXQ_IPV6) {
1766 ipv6 = (void *)((uintptr_t)parser->queue[i].ibv_attr +
1767 parser->queue[i].offset -
1768 sizeof(struct ibv_flow_spec_ipv6));
1769 if (ipv6->mask.next_hdr &&
1770 ipv6->val.next_hdr != MLX5_GRE)
1772 ipv6->val.next_hdr = MLX5_GRE;
1773 ipv6->mask.next_hdr = 0xff;
1776 if (i != hash_rxq_init_n)
1777 return rte_flow_error_set(data->error, EINVAL,
1778 RTE_FLOW_ERROR_TYPE_ITEM,
1780 "IP protocol of GRE must be 47");
1781 mlx5_flow_create_copy(parser, &tunnel, size);
1786 * Convert mark/flag action to Verbs specification.
1789 * Internal parser structure.
1794 * 0 on success, a negative errno value otherwise and rte_errno is set.
1797 mlx5_flow_create_flag_mark(struct mlx5_flow_parse *parser, uint32_t mark_id)
1799 unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
1800 struct ibv_flow_spec_action_tag tag = {
1801 .type = IBV_FLOW_SPEC_ACTION_TAG,
1803 .tag_id = mlx5_flow_mark_set(mark_id),
1806 assert(parser->mark);
1807 mlx5_flow_create_copy(parser, &tag, size);
1812 * Convert count action to Verbs specification.
1815 * Pointer to Ethernet device.
1817 * Pointer to MLX5 flow parser structure.
1820 * 0 on success, a negative errno value otherwise and rte_errno is set.
1823 mlx5_flow_create_count(struct rte_eth_dev *dev __rte_unused,
1824 struct mlx5_flow_parse *parser __rte_unused)
1826 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
1827 struct priv *priv = dev->data->dev_private;
1828 unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
1829 struct ibv_counter_set_init_attr init_attr = {0};
1830 struct ibv_flow_spec_counter_action counter = {
1831 .type = IBV_FLOW_SPEC_ACTION_COUNT,
1833 .counter_set_handle = 0,
1836 init_attr.counter_set_id = 0;
1837 parser->cs = mlx5_glue->create_counter_set(priv->ctx, &init_attr);
1842 counter.counter_set_handle = parser->cs->handle;
1843 mlx5_flow_create_copy(parser, &counter, size);
1849 * Complete flow rule creation with a drop queue.
1852 * Pointer to Ethernet device.
1854 * Internal parser structure.
1856 * Pointer to the rte_flow.
1858 * Perform verbose error reporting if not NULL.
1861 * 0 on success, a negative errno value otherwise and rte_errno is set.
1864 mlx5_flow_create_action_queue_drop(struct rte_eth_dev *dev,
1865 struct mlx5_flow_parse *parser,
1866 struct rte_flow *flow,
1867 struct rte_flow_error *error)
1869 struct priv *priv = dev->data->dev_private;
1870 struct ibv_flow_spec_action_drop *drop;
1871 unsigned int size = sizeof(struct ibv_flow_spec_action_drop);
1876 drop = (void *)((uintptr_t)parser->queue[HASH_RXQ_ETH].ibv_attr +
1877 parser->queue[HASH_RXQ_ETH].offset);
1878 *drop = (struct ibv_flow_spec_action_drop){
1879 .type = IBV_FLOW_SPEC_ACTION_DROP,
1882 ++parser->queue[HASH_RXQ_ETH].ibv_attr->num_of_specs;
1883 parser->queue[HASH_RXQ_ETH].offset += size;
1884 flow->frxq[HASH_RXQ_ETH].ibv_attr =
1885 parser->queue[HASH_RXQ_ETH].ibv_attr;
1887 flow->cs = parser->cs;
1888 if (!priv->dev->data->dev_started)
1890 parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
1891 flow->frxq[HASH_RXQ_ETH].ibv_flow =
1892 mlx5_glue->create_flow(priv->flow_drop_queue->qp,
1893 flow->frxq[HASH_RXQ_ETH].ibv_attr);
1894 if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
1895 rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1896 NULL, "flow rule creation failure");
1902 if (flow->frxq[HASH_RXQ_ETH].ibv_flow) {
1903 claim_zero(mlx5_glue->destroy_flow
1904 (flow->frxq[HASH_RXQ_ETH].ibv_flow));
1905 flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
1907 if (flow->frxq[HASH_RXQ_ETH].ibv_attr) {
1908 rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
1909 flow->frxq[HASH_RXQ_ETH].ibv_attr = NULL;
1912 claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
1920 * Create hash Rx queues when RSS is enabled.
1923 * Pointer to Ethernet device.
1925 * Internal parser structure.
1927 * Pointer to the rte_flow.
1929 * Perform verbose error reporting if not NULL.
1932 * 0 on success, a negative errno value otherwise and rte_errno is set.
1935 mlx5_flow_create_action_queue_rss(struct rte_eth_dev *dev,
1936 struct mlx5_flow_parse *parser,
1937 struct rte_flow *flow,
1938 struct rte_flow_error *error)
1940 struct priv *priv = dev->data->dev_private;
1943 for (i = 0; i != hash_rxq_init_n; ++i) {
1944 uint64_t hash_fields;
1946 if (!parser->queue[i].ibv_attr)
1948 flow->frxq[i].ibv_attr = parser->queue[i].ibv_attr;
1949 parser->queue[i].ibv_attr = NULL;
1950 hash_fields = hash_rxq_init[i].hash_fields;
1951 if (!priv->dev->data->dev_started)
1953 flow->frxq[i].hrxq =
1955 parser->rss_conf.key,
1956 parser->rss_conf.key_len,
1958 parser->rss_conf.queue,
1959 parser->rss_conf.queue_num,
1961 if (flow->frxq[i].hrxq)
1963 flow->frxq[i].hrxq =
1965 parser->rss_conf.key,
1966 parser->rss_conf.key_len,
1968 parser->rss_conf.queue,
1969 parser->rss_conf.queue_num,
1971 if (!flow->frxq[i].hrxq) {
1972 return rte_flow_error_set(error, ENOMEM,
1973 RTE_FLOW_ERROR_TYPE_HANDLE,
1975 "cannot create hash rxq");
1982 * RXQ update after flow rule creation.
1985 * Pointer to Ethernet device.
1987 * Pointer to the flow rule.
1990 mlx5_flow_create_update_rxqs(struct rte_eth_dev *dev, struct rte_flow *flow)
1992 struct priv *priv = dev->data->dev_private;
1996 if (!dev->data->dev_started)
1998 for (i = 0; i != flow->rss_conf.queue_num; ++i) {
1999 struct mlx5_rxq_data *rxq_data = (*priv->rxqs)
2000 [(*flow->queues)[i]];
2001 struct mlx5_rxq_ctrl *rxq_ctrl =
2002 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
2003 uint8_t tunnel = PTYPE_IDX(flow->tunnel);
2005 rxq_data->mark |= flow->mark;
2008 rxq_ctrl->tunnel_types[tunnel] += 1;
2009 /* Clear tunnel type if more than one tunnel types set. */
2010 for (j = 0; j != RTE_DIM(rxq_ctrl->tunnel_types); ++j) {
2013 if (rxq_ctrl->tunnel_types[j] > 0) {
2014 rxq_data->tunnel = 0;
2018 if (j == RTE_DIM(rxq_ctrl->tunnel_types))
2019 rxq_data->tunnel = flow->tunnel;
2024 * Complete flow rule creation.
2027 * Pointer to Ethernet device.
2029 * Internal parser structure.
2031 * Pointer to the rte_flow.
2033 * Perform verbose error reporting if not NULL.
2036 * 0 on success, a negative errno value otherwise and rte_errno is set.
2039 mlx5_flow_create_action_queue(struct rte_eth_dev *dev,
2040 struct mlx5_flow_parse *parser,
2041 struct rte_flow *flow,
2042 struct rte_flow_error *error)
2044 struct priv *priv = dev->data->dev_private;
2047 unsigned int flows_n = 0;
2051 assert(!parser->drop);
2052 ret = mlx5_flow_create_action_queue_rss(dev, parser, flow, error);
2056 flow->cs = parser->cs;
2057 if (!priv->dev->data->dev_started)
2059 for (i = 0; i != hash_rxq_init_n; ++i) {
2060 if (!flow->frxq[i].hrxq)
2062 flow->frxq[i].ibv_flow =
2063 mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
2064 flow->frxq[i].ibv_attr);
2065 if (!flow->frxq[i].ibv_flow) {
2066 rte_flow_error_set(error, ENOMEM,
2067 RTE_FLOW_ERROR_TYPE_HANDLE,
2068 NULL, "flow rule creation failure");
2072 DRV_LOG(DEBUG, "port %u %p type %d QP %p ibv_flow %p",
2075 (void *)flow->frxq[i].hrxq,
2076 (void *)flow->frxq[i].ibv_flow);
2079 rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE,
2080 NULL, "internal error in flow creation");
2083 mlx5_flow_create_update_rxqs(dev, flow);
2086 ret = rte_errno; /* Save rte_errno before cleanup. */
2088 for (i = 0; i != hash_rxq_init_n; ++i) {
2089 if (flow->frxq[i].ibv_flow) {
2090 struct ibv_flow *ibv_flow = flow->frxq[i].ibv_flow;
2092 claim_zero(mlx5_glue->destroy_flow(ibv_flow));
2094 if (flow->frxq[i].hrxq)
2095 mlx5_hrxq_release(dev, flow->frxq[i].hrxq);
2096 if (flow->frxq[i].ibv_attr)
2097 rte_free(flow->frxq[i].ibv_attr);
2100 claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
2104 rte_errno = ret; /* Restore rte_errno. */
2112 * Pointer to Ethernet device.
2114 * Pointer to a TAILQ flow list.
2116 * Flow rule attributes.
2117 * @param[in] pattern
2118 * Pattern specification (list terminated by the END pattern item).
2119 * @param[in] actions
2120 * Associated actions (list terminated by the END action).
2122 * Perform verbose error reporting if not NULL.
2125 * A flow on success, NULL otherwise and rte_errno is set.
2127 static struct rte_flow *
2128 mlx5_flow_list_create(struct rte_eth_dev *dev,
2129 struct mlx5_flows *list,
2130 const struct rte_flow_attr *attr,
2131 const struct rte_flow_item items[],
2132 const struct rte_flow_action actions[],
2133 struct rte_flow_error *error)
2135 struct mlx5_flow_parse parser = { .create = 1, };
2136 struct rte_flow *flow = NULL;
2140 ret = mlx5_flow_convert(dev, attr, items, actions, error, &parser);
2143 flow = rte_calloc(__func__, 1,
2145 parser.rss_conf.queue_num * sizeof(uint16_t),
2148 rte_flow_error_set(error, ENOMEM,
2149 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2151 "cannot allocate flow memory");
2154 /* Copy configuration. */
2155 flow->queues = (uint16_t (*)[])(flow + 1);
2156 flow->tunnel = parser.tunnel;
2157 flow->rss_conf = (struct rte_flow_action_rss){
2158 .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
2160 .types = parser.rss_conf.types,
2161 .key_len = parser.rss_conf.key_len,
2162 .queue_num = parser.rss_conf.queue_num,
2163 .key = memcpy(flow->rss_key, parser.rss_conf.key,
2164 sizeof(*parser.rss_conf.key) *
2165 parser.rss_conf.key_len),
2166 .queue = memcpy(flow->queues, parser.rss_conf.queue,
2167 sizeof(*parser.rss_conf.queue) *
2168 parser.rss_conf.queue_num),
2170 flow->mark = parser.mark;
2171 /* finalise the flow. */
2173 ret = mlx5_flow_create_action_queue_drop(dev, &parser, flow,
2176 ret = mlx5_flow_create_action_queue(dev, &parser, flow, error);
2179 TAILQ_INSERT_TAIL(list, flow, next);
2180 DRV_LOG(DEBUG, "port %u flow created %p", dev->data->port_id,
2184 DRV_LOG(ERR, "port %u flow creation error: %s", dev->data->port_id,
2186 for (i = 0; i != hash_rxq_init_n; ++i) {
2187 if (parser.queue[i].ibv_attr)
2188 rte_free(parser.queue[i].ibv_attr);
2195 * Validate a flow supported by the NIC.
2197 * @see rte_flow_validate()
2201 mlx5_flow_validate(struct rte_eth_dev *dev,
2202 const struct rte_flow_attr *attr,
2203 const struct rte_flow_item items[],
2204 const struct rte_flow_action actions[],
2205 struct rte_flow_error *error)
2207 struct mlx5_flow_parse parser = { .create = 0, };
2209 return mlx5_flow_convert(dev, attr, items, actions, error, &parser);
2215 * @see rte_flow_create()
2219 mlx5_flow_create(struct rte_eth_dev *dev,
2220 const struct rte_flow_attr *attr,
2221 const struct rte_flow_item items[],
2222 const struct rte_flow_action actions[],
2223 struct rte_flow_error *error)
2225 struct priv *priv = dev->data->dev_private;
2227 return mlx5_flow_list_create(dev, &priv->flows, attr, items, actions,
2232 * Destroy a flow in a list.
2235 * Pointer to Ethernet device.
2237 * Pointer to a TAILQ flow list.
2242 mlx5_flow_list_destroy(struct rte_eth_dev *dev, struct mlx5_flows *list,
2243 struct rte_flow *flow)
2245 struct priv *priv = dev->data->dev_private;
2248 if (flow->drop || !dev->data->dev_started)
2250 for (i = 0; flow->tunnel && i != flow->rss_conf.queue_num; ++i) {
2251 /* Update queue tunnel type. */
2252 struct mlx5_rxq_data *rxq_data = (*priv->rxqs)
2253 [(*flow->queues)[i]];
2254 struct mlx5_rxq_ctrl *rxq_ctrl =
2255 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
2256 uint8_t tunnel = PTYPE_IDX(flow->tunnel);
2258 assert(rxq_ctrl->tunnel_types[tunnel] > 0);
2259 rxq_ctrl->tunnel_types[tunnel] -= 1;
2260 if (!rxq_ctrl->tunnel_types[tunnel]) {
2261 /* Update tunnel type. */
2266 for (j = 0; j < RTE_DIM(rxq_ctrl->tunnel_types); j++)
2267 if (rxq_ctrl->tunnel_types[j]) {
2271 /* Keep same if more than one tunnel types left. */
2273 rxq_data->tunnel = ptype_ext[last];
2274 else if (types == 0)
2275 /* No tunnel type left. */
2276 rxq_data->tunnel = 0;
2279 for (i = 0; flow->mark && i != flow->rss_conf.queue_num; ++i) {
2280 struct rte_flow *tmp;
2284 * To remove the mark from the queue, the queue must not be
2285 * present in any other marked flow (RSS or not).
2287 TAILQ_FOREACH(tmp, list, next) {
2289 uint16_t *tqs = NULL;
2294 for (j = 0; j != hash_rxq_init_n; ++j) {
2295 if (!tmp->frxq[j].hrxq)
2297 tqs = tmp->frxq[j].hrxq->ind_table->queues;
2298 tq_n = tmp->frxq[j].hrxq->ind_table->queues_n;
2302 for (j = 0; (j != tq_n) && !mark; j++)
2303 if (tqs[j] == (*flow->queues)[i])
2306 (*priv->rxqs)[(*flow->queues)[i]]->mark = mark;
2310 if (flow->frxq[HASH_RXQ_ETH].ibv_flow)
2311 claim_zero(mlx5_glue->destroy_flow
2312 (flow->frxq[HASH_RXQ_ETH].ibv_flow));
2313 rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
2315 for (i = 0; i != hash_rxq_init_n; ++i) {
2316 struct mlx5_flow *frxq = &flow->frxq[i];
2319 claim_zero(mlx5_glue->destroy_flow
2322 mlx5_hrxq_release(dev, frxq->hrxq);
2324 rte_free(frxq->ibv_attr);
2328 claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
2331 TAILQ_REMOVE(list, flow, next);
2332 DRV_LOG(DEBUG, "port %u flow destroyed %p", dev->data->port_id,
2338 * Destroy all flows.
2341 * Pointer to Ethernet device.
2343 * Pointer to a TAILQ flow list.
2346 mlx5_flow_list_flush(struct rte_eth_dev *dev, struct mlx5_flows *list)
2348 while (!TAILQ_EMPTY(list)) {
2349 struct rte_flow *flow;
2351 flow = TAILQ_FIRST(list);
2352 mlx5_flow_list_destroy(dev, list, flow);
2357 * Create drop queue.
2360 * Pointer to Ethernet device.
2363 * 0 on success, a negative errno value otherwise and rte_errno is set.
2366 mlx5_flow_create_drop_queue(struct rte_eth_dev *dev)
2368 struct priv *priv = dev->data->dev_private;
2369 struct mlx5_hrxq_drop *fdq = NULL;
2373 fdq = rte_calloc(__func__, 1, sizeof(*fdq), 0);
2376 "port %u cannot allocate memory for drop queue",
2377 dev->data->port_id);
2381 fdq->cq = mlx5_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
2383 DRV_LOG(WARNING, "port %u cannot allocate CQ for drop queue",
2384 dev->data->port_id);
2388 fdq->wq = mlx5_glue->create_wq
2390 &(struct ibv_wq_init_attr){
2391 .wq_type = IBV_WQT_RQ,
2398 DRV_LOG(WARNING, "port %u cannot allocate WQ for drop queue",
2399 dev->data->port_id);
2403 fdq->ind_table = mlx5_glue->create_rwq_ind_table
2405 &(struct ibv_rwq_ind_table_init_attr){
2406 .log_ind_tbl_size = 0,
2407 .ind_tbl = &fdq->wq,
2410 if (!fdq->ind_table) {
2412 "port %u cannot allocate indirection table for drop"
2414 dev->data->port_id);
2418 fdq->qp = mlx5_glue->create_qp_ex
2420 &(struct ibv_qp_init_attr_ex){
2421 .qp_type = IBV_QPT_RAW_PACKET,
2423 IBV_QP_INIT_ATTR_PD |
2424 IBV_QP_INIT_ATTR_IND_TABLE |
2425 IBV_QP_INIT_ATTR_RX_HASH,
2426 .rx_hash_conf = (struct ibv_rx_hash_conf){
2428 IBV_RX_HASH_FUNC_TOEPLITZ,
2429 .rx_hash_key_len = rss_hash_default_key_len,
2430 .rx_hash_key = rss_hash_default_key,
2431 .rx_hash_fields_mask = 0,
2433 .rwq_ind_tbl = fdq->ind_table,
2437 DRV_LOG(WARNING, "port %u cannot allocate QP for drop queue",
2438 dev->data->port_id);
2442 priv->flow_drop_queue = fdq;
2446 claim_zero(mlx5_glue->destroy_qp(fdq->qp));
2448 claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
2450 claim_zero(mlx5_glue->destroy_wq(fdq->wq));
2452 claim_zero(mlx5_glue->destroy_cq(fdq->cq));
2455 priv->flow_drop_queue = NULL;
2460 * Delete drop queue.
2463 * Pointer to Ethernet device.
2466 mlx5_flow_delete_drop_queue(struct rte_eth_dev *dev)
2468 struct priv *priv = dev->data->dev_private;
2469 struct mlx5_hrxq_drop *fdq = priv->flow_drop_queue;
2474 claim_zero(mlx5_glue->destroy_qp(fdq->qp));
2476 claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
2478 claim_zero(mlx5_glue->destroy_wq(fdq->wq));
2480 claim_zero(mlx5_glue->destroy_cq(fdq->cq));
2482 priv->flow_drop_queue = NULL;
2489 * Pointer to Ethernet device.
2491 * Pointer to a TAILQ flow list.
2494 mlx5_flow_stop(struct rte_eth_dev *dev, struct mlx5_flows *list)
2496 struct priv *priv = dev->data->dev_private;
2497 struct rte_flow *flow;
2500 TAILQ_FOREACH_REVERSE(flow, list, mlx5_flows, next) {
2501 struct mlx5_ind_table_ibv *ind_tbl = NULL;
2504 if (!flow->frxq[HASH_RXQ_ETH].ibv_flow)
2506 claim_zero(mlx5_glue->destroy_flow
2507 (flow->frxq[HASH_RXQ_ETH].ibv_flow));
2508 flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
2509 DRV_LOG(DEBUG, "port %u flow %p removed",
2510 dev->data->port_id, (void *)flow);
2514 /* Verify the flow has not already been cleaned. */
2515 for (i = 0; i != hash_rxq_init_n; ++i) {
2516 if (!flow->frxq[i].ibv_flow)
2519 * Indirection table may be necessary to remove the
2520 * flags in the Rx queues.
2521 * This helps to speed-up the process by avoiding
2524 ind_tbl = flow->frxq[i].hrxq->ind_table;
2527 if (i == hash_rxq_init_n)
2531 for (i = 0; i != ind_tbl->queues_n; ++i)
2532 (*priv->rxqs)[ind_tbl->queues[i]]->mark = 0;
2534 for (i = 0; i != hash_rxq_init_n; ++i) {
2535 if (!flow->frxq[i].ibv_flow)
2537 claim_zero(mlx5_glue->destroy_flow
2538 (flow->frxq[i].ibv_flow));
2539 flow->frxq[i].ibv_flow = NULL;
2540 mlx5_hrxq_release(dev, flow->frxq[i].hrxq);
2541 flow->frxq[i].hrxq = NULL;
2543 DRV_LOG(DEBUG, "port %u flow %p removed", dev->data->port_id,
2546 /* Cleanup Rx queue tunnel info. */
2547 for (i = 0; i != priv->rxqs_n; ++i) {
2548 struct mlx5_rxq_data *q = (*priv->rxqs)[i];
2549 struct mlx5_rxq_ctrl *rxq_ctrl =
2550 container_of(q, struct mlx5_rxq_ctrl, rxq);
2554 memset((void *)rxq_ctrl->tunnel_types, 0,
2555 sizeof(rxq_ctrl->tunnel_types));
2564 * Pointer to Ethernet device.
2566 * Pointer to a TAILQ flow list.
2569 * 0 on success, a negative errno value otherwise and rte_errno is set.
2572 mlx5_flow_start(struct rte_eth_dev *dev, struct mlx5_flows *list)
2574 struct priv *priv = dev->data->dev_private;
2575 struct rte_flow *flow;
2577 TAILQ_FOREACH(flow, list, next) {
2581 flow->frxq[HASH_RXQ_ETH].ibv_flow =
2582 mlx5_glue->create_flow
2583 (priv->flow_drop_queue->qp,
2584 flow->frxq[HASH_RXQ_ETH].ibv_attr);
2585 if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
2587 "port %u flow %p cannot be applied",
2588 dev->data->port_id, (void *)flow);
2592 DRV_LOG(DEBUG, "port %u flow %p applied",
2593 dev->data->port_id, (void *)flow);
2597 for (i = 0; i != hash_rxq_init_n; ++i) {
2598 if (!flow->frxq[i].ibv_attr)
2600 flow->frxq[i].hrxq =
2601 mlx5_hrxq_get(dev, flow->rss_conf.key,
2602 flow->rss_conf.key_len,
2603 hash_rxq_init[i].hash_fields,
2604 flow->rss_conf.queue,
2605 flow->rss_conf.queue_num,
2607 if (flow->frxq[i].hrxq)
2609 flow->frxq[i].hrxq =
2610 mlx5_hrxq_new(dev, flow->rss_conf.key,
2611 flow->rss_conf.key_len,
2612 hash_rxq_init[i].hash_fields,
2613 flow->rss_conf.queue,
2614 flow->rss_conf.queue_num,
2616 if (!flow->frxq[i].hrxq) {
2618 "port %u flow %p cannot be applied",
2619 dev->data->port_id, (void *)flow);
2624 flow->frxq[i].ibv_flow =
2625 mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
2626 flow->frxq[i].ibv_attr);
2627 if (!flow->frxq[i].ibv_flow) {
2629 "port %u flow %p cannot be applied",
2630 dev->data->port_id, (void *)flow);
2634 DRV_LOG(DEBUG, "port %u flow %p applied",
2635 dev->data->port_id, (void *)flow);
2637 mlx5_flow_create_update_rxqs(dev, flow);
2643 * Verify the flow list is empty
2646 * Pointer to Ethernet device.
2648 * @return the number of flows not released.
2651 mlx5_flow_verify(struct rte_eth_dev *dev)
2653 struct priv *priv = dev->data->dev_private;
2654 struct rte_flow *flow;
2657 TAILQ_FOREACH(flow, &priv->flows, next) {
2658 DRV_LOG(DEBUG, "port %u flow %p still referenced",
2659 dev->data->port_id, (void *)flow);
2666 * Enable a control flow configured from the control plane.
2669 * Pointer to Ethernet device.
2671 * An Ethernet flow spec to apply.
2673 * An Ethernet flow mask to apply.
2675 * A VLAN flow spec to apply.
2677 * A VLAN flow mask to apply.
2680 * 0 on success, a negative errno value otherwise and rte_errno is set.
2683 mlx5_ctrl_flow_vlan(struct rte_eth_dev *dev,
2684 struct rte_flow_item_eth *eth_spec,
2685 struct rte_flow_item_eth *eth_mask,
2686 struct rte_flow_item_vlan *vlan_spec,
2687 struct rte_flow_item_vlan *vlan_mask)
2689 struct priv *priv = dev->data->dev_private;
2690 const struct rte_flow_attr attr = {
2692 .priority = MLX5_CTRL_FLOW_PRIORITY,
2694 struct rte_flow_item items[] = {
2696 .type = RTE_FLOW_ITEM_TYPE_ETH,
2702 .type = (vlan_spec) ? RTE_FLOW_ITEM_TYPE_VLAN :
2703 RTE_FLOW_ITEM_TYPE_END,
2709 .type = RTE_FLOW_ITEM_TYPE_END,
2712 uint16_t queue[priv->reta_idx_n];
2713 struct rte_flow_action_rss action_rss = {
2714 .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
2716 .types = priv->rss_conf.rss_hf,
2717 .key_len = priv->rss_conf.rss_key_len,
2718 .queue_num = priv->reta_idx_n,
2719 .key = priv->rss_conf.rss_key,
2722 struct rte_flow_action actions[] = {
2724 .type = RTE_FLOW_ACTION_TYPE_RSS,
2725 .conf = &action_rss,
2728 .type = RTE_FLOW_ACTION_TYPE_END,
2731 struct rte_flow *flow;
2732 struct rte_flow_error error;
2735 if (!priv->reta_idx_n) {
2739 for (i = 0; i != priv->reta_idx_n; ++i)
2740 queue[i] = (*priv->reta_idx)[i];
2741 flow = mlx5_flow_list_create(dev, &priv->ctrl_flows, &attr, items,
2749 * Enable a flow control configured from the control plane.
2752 * Pointer to Ethernet device.
2754 * An Ethernet flow spec to apply.
2756 * An Ethernet flow mask to apply.
2759 * 0 on success, a negative errno value otherwise and rte_errno is set.
2762 mlx5_ctrl_flow(struct rte_eth_dev *dev,
2763 struct rte_flow_item_eth *eth_spec,
2764 struct rte_flow_item_eth *eth_mask)
2766 return mlx5_ctrl_flow_vlan(dev, eth_spec, eth_mask, NULL, NULL);
2772 * @see rte_flow_destroy()
2776 mlx5_flow_destroy(struct rte_eth_dev *dev,
2777 struct rte_flow *flow,
2778 struct rte_flow_error *error __rte_unused)
2780 struct priv *priv = dev->data->dev_private;
2782 mlx5_flow_list_destroy(dev, &priv->flows, flow);
2787 * Destroy all flows.
2789 * @see rte_flow_flush()
2793 mlx5_flow_flush(struct rte_eth_dev *dev,
2794 struct rte_flow_error *error __rte_unused)
2796 struct priv *priv = dev->data->dev_private;
2798 mlx5_flow_list_flush(dev, &priv->flows);
2802 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
2804 * Query flow counter.
2808 * @param counter_value
2809 * returned data from the counter.
2812 * 0 on success, a negative errno value otherwise and rte_errno is set.
2815 mlx5_flow_query_count(struct ibv_counter_set *cs,
2816 struct mlx5_flow_counter_stats *counter_stats,
2817 struct rte_flow_query_count *query_count,
2818 struct rte_flow_error *error)
2820 uint64_t counters[2];
2821 struct ibv_query_counter_set_attr query_cs_attr = {
2823 .query_flags = IBV_COUNTER_SET_FORCE_UPDATE,
2825 struct ibv_counter_set_data query_out = {
2827 .outlen = 2 * sizeof(uint64_t),
2829 int err = mlx5_glue->query_counter_set(&query_cs_attr, &query_out);
2832 return rte_flow_error_set(error, err,
2833 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2835 "cannot read counter");
2836 query_count->hits_set = 1;
2837 query_count->bytes_set = 1;
2838 query_count->hits = counters[0] - counter_stats->hits;
2839 query_count->bytes = counters[1] - counter_stats->bytes;
2840 if (query_count->reset) {
2841 counter_stats->hits = counters[0];
2842 counter_stats->bytes = counters[1];
2850 * @see rte_flow_query()
2854 mlx5_flow_query(struct rte_eth_dev *dev __rte_unused,
2855 struct rte_flow *flow,
2856 enum rte_flow_action_type action __rte_unused,
2858 struct rte_flow_error *error)
2863 ret = mlx5_flow_query_count(flow->cs,
2864 &flow->counter_stats,
2865 (struct rte_flow_query_count *)data,
2870 return rte_flow_error_set(error, EINVAL,
2871 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2873 "no counter found for flow");
2882 * @see rte_flow_isolate()
2886 mlx5_flow_isolate(struct rte_eth_dev *dev,
2888 struct rte_flow_error *error)
2890 struct priv *priv = dev->data->dev_private;
2892 if (dev->data->dev_started) {
2893 rte_flow_error_set(error, EBUSY,
2894 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2896 "port must be stopped first");
2899 priv->isolated = !!enable;
2901 priv->dev->dev_ops = &mlx5_dev_ops_isolate;
2903 priv->dev->dev_ops = &mlx5_dev_ops;
2908 * Convert a flow director filter to a generic flow.
2911 * Pointer to Ethernet device.
2912 * @param fdir_filter
2913 * Flow director filter to add.
2915 * Generic flow parameters structure.
2918 * 0 on success, a negative errno value otherwise and rte_errno is set.
2921 mlx5_fdir_filter_convert(struct rte_eth_dev *dev,
2922 const struct rte_eth_fdir_filter *fdir_filter,
2923 struct mlx5_fdir *attributes)
2925 struct priv *priv = dev->data->dev_private;
2926 const struct rte_eth_fdir_input *input = &fdir_filter->input;
2927 const struct rte_eth_fdir_masks *mask =
2928 &dev->data->dev_conf.fdir_conf.mask;
2930 /* Validate queue number. */
2931 if (fdir_filter->action.rx_queue >= priv->rxqs_n) {
2932 DRV_LOG(ERR, "port %u invalid queue number %d",
2933 dev->data->port_id, fdir_filter->action.rx_queue);
2937 attributes->attr.ingress = 1;
2938 attributes->items[0] = (struct rte_flow_item) {
2939 .type = RTE_FLOW_ITEM_TYPE_ETH,
2940 .spec = &attributes->l2,
2941 .mask = &attributes->l2_mask,
2943 switch (fdir_filter->action.behavior) {
2944 case RTE_ETH_FDIR_ACCEPT:
2945 attributes->actions[0] = (struct rte_flow_action){
2946 .type = RTE_FLOW_ACTION_TYPE_QUEUE,
2947 .conf = &attributes->queue,
2950 case RTE_ETH_FDIR_REJECT:
2951 attributes->actions[0] = (struct rte_flow_action){
2952 .type = RTE_FLOW_ACTION_TYPE_DROP,
2956 DRV_LOG(ERR, "port %u invalid behavior %d",
2958 fdir_filter->action.behavior);
2959 rte_errno = ENOTSUP;
2962 attributes->queue.index = fdir_filter->action.rx_queue;
2964 switch (fdir_filter->input.flow_type) {
2965 case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
2966 case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
2967 case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
2968 attributes->l3.ipv4.hdr = (struct ipv4_hdr){
2969 .src_addr = input->flow.ip4_flow.src_ip,
2970 .dst_addr = input->flow.ip4_flow.dst_ip,
2971 .time_to_live = input->flow.ip4_flow.ttl,
2972 .type_of_service = input->flow.ip4_flow.tos,
2973 .next_proto_id = input->flow.ip4_flow.proto,
2975 attributes->l3_mask.ipv4.hdr = (struct ipv4_hdr){
2976 .src_addr = mask->ipv4_mask.src_ip,
2977 .dst_addr = mask->ipv4_mask.dst_ip,
2978 .time_to_live = mask->ipv4_mask.ttl,
2979 .type_of_service = mask->ipv4_mask.tos,
2980 .next_proto_id = mask->ipv4_mask.proto,
2982 attributes->items[1] = (struct rte_flow_item){
2983 .type = RTE_FLOW_ITEM_TYPE_IPV4,
2984 .spec = &attributes->l3,
2985 .mask = &attributes->l3_mask,
2988 case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
2989 case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
2990 case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
2991 attributes->l3.ipv6.hdr = (struct ipv6_hdr){
2992 .hop_limits = input->flow.ipv6_flow.hop_limits,
2993 .proto = input->flow.ipv6_flow.proto,
2996 memcpy(attributes->l3.ipv6.hdr.src_addr,
2997 input->flow.ipv6_flow.src_ip,
2998 RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
2999 memcpy(attributes->l3.ipv6.hdr.dst_addr,
3000 input->flow.ipv6_flow.dst_ip,
3001 RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
3002 memcpy(attributes->l3_mask.ipv6.hdr.src_addr,
3003 mask->ipv6_mask.src_ip,
3004 RTE_DIM(attributes->l3_mask.ipv6.hdr.src_addr));
3005 memcpy(attributes->l3_mask.ipv6.hdr.dst_addr,
3006 mask->ipv6_mask.dst_ip,
3007 RTE_DIM(attributes->l3_mask.ipv6.hdr.src_addr));
3008 attributes->items[1] = (struct rte_flow_item){
3009 .type = RTE_FLOW_ITEM_TYPE_IPV6,
3010 .spec = &attributes->l3,
3011 .mask = &attributes->l3_mask,
3015 DRV_LOG(ERR, "port %u invalid flow type%d",
3016 dev->data->port_id, fdir_filter->input.flow_type);
3017 rte_errno = ENOTSUP;
3021 switch (fdir_filter->input.flow_type) {
3022 case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
3023 attributes->l4.udp.hdr = (struct udp_hdr){
3024 .src_port = input->flow.udp4_flow.src_port,
3025 .dst_port = input->flow.udp4_flow.dst_port,
3027 attributes->l4_mask.udp.hdr = (struct udp_hdr){
3028 .src_port = mask->src_port_mask,
3029 .dst_port = mask->dst_port_mask,
3031 attributes->items[2] = (struct rte_flow_item){
3032 .type = RTE_FLOW_ITEM_TYPE_UDP,
3033 .spec = &attributes->l4,
3034 .mask = &attributes->l4_mask,
3037 case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
3038 attributes->l4.tcp.hdr = (struct tcp_hdr){
3039 .src_port = input->flow.tcp4_flow.src_port,
3040 .dst_port = input->flow.tcp4_flow.dst_port,
3042 attributes->l4_mask.tcp.hdr = (struct tcp_hdr){
3043 .src_port = mask->src_port_mask,
3044 .dst_port = mask->dst_port_mask,
3046 attributes->items[2] = (struct rte_flow_item){
3047 .type = RTE_FLOW_ITEM_TYPE_TCP,
3048 .spec = &attributes->l4,
3049 .mask = &attributes->l4_mask,
3052 case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
3053 attributes->l4.udp.hdr = (struct udp_hdr){
3054 .src_port = input->flow.udp6_flow.src_port,
3055 .dst_port = input->flow.udp6_flow.dst_port,
3057 attributes->l4_mask.udp.hdr = (struct udp_hdr){
3058 .src_port = mask->src_port_mask,
3059 .dst_port = mask->dst_port_mask,
3061 attributes->items[2] = (struct rte_flow_item){
3062 .type = RTE_FLOW_ITEM_TYPE_UDP,
3063 .spec = &attributes->l4,
3064 .mask = &attributes->l4_mask,
3067 case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
3068 attributes->l4.tcp.hdr = (struct tcp_hdr){
3069 .src_port = input->flow.tcp6_flow.src_port,
3070 .dst_port = input->flow.tcp6_flow.dst_port,
3072 attributes->l4_mask.tcp.hdr = (struct tcp_hdr){
3073 .src_port = mask->src_port_mask,
3074 .dst_port = mask->dst_port_mask,
3076 attributes->items[2] = (struct rte_flow_item){
3077 .type = RTE_FLOW_ITEM_TYPE_TCP,
3078 .spec = &attributes->l4,
3079 .mask = &attributes->l4_mask,
3082 case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
3083 case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
3086 DRV_LOG(ERR, "port %u invalid flow type%d",
3087 dev->data->port_id, fdir_filter->input.flow_type);
3088 rte_errno = ENOTSUP;
3095 * Add new flow director filter and store it in list.
3098 * Pointer to Ethernet device.
3099 * @param fdir_filter
3100 * Flow director filter to add.
3103 * 0 on success, a negative errno value otherwise and rte_errno is set.
3106 mlx5_fdir_filter_add(struct rte_eth_dev *dev,
3107 const struct rte_eth_fdir_filter *fdir_filter)
3109 struct priv *priv = dev->data->dev_private;
3110 struct mlx5_fdir attributes = {
3113 .dst.addr_bytes = "\x00\x00\x00\x00\x00\x00",
3114 .src.addr_bytes = "\x00\x00\x00\x00\x00\x00",
3118 struct mlx5_flow_parse parser = {
3119 .layer = HASH_RXQ_ETH,
3121 struct rte_flow_error error;
3122 struct rte_flow *flow;
3125 ret = mlx5_fdir_filter_convert(dev, fdir_filter, &attributes);
3128 ret = mlx5_flow_convert(dev, &attributes.attr, attributes.items,
3129 attributes.actions, &error, &parser);
3132 flow = mlx5_flow_list_create(dev, &priv->flows, &attributes.attr,
3133 attributes.items, attributes.actions,
3136 DRV_LOG(DEBUG, "port %u FDIR created %p", dev->data->port_id,
3144 * Delete specific filter.
3147 * Pointer to Ethernet device.
3148 * @param fdir_filter
3149 * Filter to be deleted.
3152 * 0 on success, a negative errno value otherwise and rte_errno is set.
3155 mlx5_fdir_filter_delete(struct rte_eth_dev *dev,
3156 const struct rte_eth_fdir_filter *fdir_filter)
3158 struct priv *priv = dev->data->dev_private;
3159 struct mlx5_fdir attributes = {
3162 struct mlx5_flow_parse parser = {
3164 .layer = HASH_RXQ_ETH,
3166 struct rte_flow_error error;
3167 struct rte_flow *flow;
3171 ret = mlx5_fdir_filter_convert(dev, fdir_filter, &attributes);
3174 ret = mlx5_flow_convert(dev, &attributes.attr, attributes.items,
3175 attributes.actions, &error, &parser);
3179 * Special case for drop action which is only set in the
3180 * specifications when the flow is created. In this situation the
3181 * drop specification is missing.
3184 struct ibv_flow_spec_action_drop *drop;
3186 drop = (void *)((uintptr_t)parser.queue[HASH_RXQ_ETH].ibv_attr +
3187 parser.queue[HASH_RXQ_ETH].offset);
3188 *drop = (struct ibv_flow_spec_action_drop){
3189 .type = IBV_FLOW_SPEC_ACTION_DROP,
3190 .size = sizeof(struct ibv_flow_spec_action_drop),
3192 parser.queue[HASH_RXQ_ETH].ibv_attr->num_of_specs++;
3194 TAILQ_FOREACH(flow, &priv->flows, next) {
3195 struct ibv_flow_attr *attr;
3196 struct ibv_spec_header *attr_h;
3198 struct ibv_flow_attr *flow_attr;
3199 struct ibv_spec_header *flow_h;
3201 unsigned int specs_n;
3203 attr = parser.queue[HASH_RXQ_ETH].ibv_attr;
3204 flow_attr = flow->frxq[HASH_RXQ_ETH].ibv_attr;
3205 /* Compare first the attributes. */
3206 if (memcmp(attr, flow_attr, sizeof(struct ibv_flow_attr)))
3208 if (attr->num_of_specs == 0)
3210 spec = (void *)((uintptr_t)attr +
3211 sizeof(struct ibv_flow_attr));
3212 flow_spec = (void *)((uintptr_t)flow_attr +
3213 sizeof(struct ibv_flow_attr));
3214 specs_n = RTE_MIN(attr->num_of_specs, flow_attr->num_of_specs);
3215 for (i = 0; i != specs_n; ++i) {
3218 if (memcmp(spec, flow_spec,
3219 RTE_MIN(attr_h->size, flow_h->size)))
3221 spec = (void *)((uintptr_t)spec + attr_h->size);
3222 flow_spec = (void *)((uintptr_t)flow_spec +
3225 /* At this point, the flow match. */
3228 /* The flow does not match. */
3231 ret = rte_errno; /* Save rte_errno before cleanup. */
3233 mlx5_flow_list_destroy(dev, &priv->flows, flow);
3235 for (i = 0; i != hash_rxq_init_n; ++i) {
3236 if (parser.queue[i].ibv_attr)
3237 rte_free(parser.queue[i].ibv_attr);
3239 rte_errno = ret; /* Restore rte_errno. */
3244 * Update queue for specific filter.
3247 * Pointer to Ethernet device.
3248 * @param fdir_filter
3249 * Filter to be updated.
3252 * 0 on success, a negative errno value otherwise and rte_errno is set.
3255 mlx5_fdir_filter_update(struct rte_eth_dev *dev,
3256 const struct rte_eth_fdir_filter *fdir_filter)
3260 ret = mlx5_fdir_filter_delete(dev, fdir_filter);
3263 return mlx5_fdir_filter_add(dev, fdir_filter);
3267 * Flush all filters.
3270 * Pointer to Ethernet device.
3273 mlx5_fdir_filter_flush(struct rte_eth_dev *dev)
3275 struct priv *priv = dev->data->dev_private;
3277 mlx5_flow_list_flush(dev, &priv->flows);
3281 * Get flow director information.
3284 * Pointer to Ethernet device.
3285 * @param[out] fdir_info
3286 * Resulting flow director information.
3289 mlx5_fdir_info_get(struct rte_eth_dev *dev, struct rte_eth_fdir_info *fdir_info)
3291 struct priv *priv = dev->data->dev_private;
3292 struct rte_eth_fdir_masks *mask =
3293 &priv->dev->data->dev_conf.fdir_conf.mask;
3295 fdir_info->mode = priv->dev->data->dev_conf.fdir_conf.mode;
3296 fdir_info->guarant_spc = 0;
3297 rte_memcpy(&fdir_info->mask, mask, sizeof(fdir_info->mask));
3298 fdir_info->max_flexpayload = 0;
3299 fdir_info->flow_types_mask[0] = 0;
3300 fdir_info->flex_payload_unit = 0;
3301 fdir_info->max_flex_payload_segment_num = 0;
3302 fdir_info->flex_payload_limit = 0;
3303 memset(&fdir_info->flex_conf, 0, sizeof(fdir_info->flex_conf));
3307 * Deal with flow director operations.
3310 * Pointer to Ethernet device.
3312 * Operation to perform.
3314 * Pointer to operation-specific structure.
3317 * 0 on success, a negative errno value otherwise and rte_errno is set.
3320 mlx5_fdir_ctrl_func(struct rte_eth_dev *dev, enum rte_filter_op filter_op,
3323 struct priv *priv = dev->data->dev_private;
3324 enum rte_fdir_mode fdir_mode =
3325 priv->dev->data->dev_conf.fdir_conf.mode;
3327 if (filter_op == RTE_ETH_FILTER_NOP)
3329 if (fdir_mode != RTE_FDIR_MODE_PERFECT &&
3330 fdir_mode != RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
3331 DRV_LOG(ERR, "port %u flow director mode %d not supported",
3332 dev->data->port_id, fdir_mode);
3336 switch (filter_op) {
3337 case RTE_ETH_FILTER_ADD:
3338 return mlx5_fdir_filter_add(dev, arg);
3339 case RTE_ETH_FILTER_UPDATE:
3340 return mlx5_fdir_filter_update(dev, arg);
3341 case RTE_ETH_FILTER_DELETE:
3342 return mlx5_fdir_filter_delete(dev, arg);
3343 case RTE_ETH_FILTER_FLUSH:
3344 mlx5_fdir_filter_flush(dev);
3346 case RTE_ETH_FILTER_INFO:
3347 mlx5_fdir_info_get(dev, arg);
3350 DRV_LOG(DEBUG, "port %u unknown operation %u",
3351 dev->data->port_id, filter_op);
3359 * Manage filter operations.
3362 * Pointer to Ethernet device structure.
3363 * @param filter_type
3366 * Operation to perform.
3368 * Pointer to operation-specific structure.
3371 * 0 on success, a negative errno value otherwise and rte_errno is set.
3374 mlx5_dev_filter_ctrl(struct rte_eth_dev *dev,
3375 enum rte_filter_type filter_type,
3376 enum rte_filter_op filter_op,
3379 switch (filter_type) {
3380 case RTE_ETH_FILTER_GENERIC:
3381 if (filter_op != RTE_ETH_FILTER_GET) {
3385 *(const void **)arg = &mlx5_flow_ops;
3387 case RTE_ETH_FILTER_FDIR:
3388 return mlx5_fdir_ctrl_func(dev, filter_op, arg);
3390 DRV_LOG(ERR, "port %u filter type (%d) not supported",
3391 dev->data->port_id, filter_type);
3392 rte_errno = ENOTSUP;
3399 * Detect number of Verbs flow priorities supported.
3402 * Pointer to Ethernet device.
3405 * number of supported Verbs flow priority.
3408 mlx5_get_max_verbs_prio(struct rte_eth_dev *dev)
3410 struct priv *priv = dev->data->dev_private;
3411 unsigned int verb_priorities = MLX5_VERBS_FLOW_PRIO_8;
3413 struct ibv_flow_attr attr;
3414 struct ibv_flow_spec_eth eth;
3415 struct ibv_flow_spec_action_drop drop;
3421 .type = IBV_FLOW_SPEC_ETH,
3422 .size = sizeof(struct ibv_flow_spec_eth),
3425 .size = sizeof(struct ibv_flow_spec_action_drop),
3426 .type = IBV_FLOW_SPEC_ACTION_DROP,
3429 struct ibv_flow *flow;
3432 flow_attr.attr.priority = verb_priorities - 1;
3433 flow = mlx5_glue->create_flow(priv->flow_drop_queue->qp,
3436 claim_zero(mlx5_glue->destroy_flow(flow));
3437 /* Try more priorities. */
3438 verb_priorities *= 2;
3440 /* Failed, restore last right number. */
3441 verb_priorities /= 2;
3445 DRV_LOG(DEBUG, "port %u Verbs flow priorities: %d,"
3446 " user flow priorities: %d",
3447 dev->data->port_id, verb_priorities, MLX5_CTRL_FLOW_PRIORITY);
3448 return verb_priorities;