1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2018 Mellanox Technologies, Ltd
5 #include <netinet/in.h>
11 #include <rte_common.h>
12 #include <rte_ether.h>
13 #include <ethdev_driver.h>
15 #include <rte_flow_driver.h>
16 #include <rte_malloc.h>
19 #include <mlx5_glue.h>
21 #include <mlx5_malloc.h>
23 #include "mlx5_defs.h"
25 #include "mlx5_flow.h"
26 #include "mlx5_rxtx.h"
29 #define VERBS_SPEC_INNER(item_flags) \
30 (!!((item_flags) & MLX5_FLOW_LAYER_TUNNEL) ? IBV_FLOW_SPEC_INNER : 0)
32 /* Map of Verbs to Flow priority with 8 Verbs priorities. */
33 static const uint32_t priority_map_3[][MLX5_PRIORITY_MAP_MAX] = {
34 { 0, 1, 2 }, { 2, 3, 4 }, { 5, 6, 7 },
37 /* Map of Verbs to Flow priority with 16 Verbs priorities. */
38 static const uint32_t priority_map_5[][MLX5_PRIORITY_MAP_MAX] = {
39 { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 },
40 { 9, 10, 11 }, { 12, 13, 14 },
43 /* Verbs specification header. */
44 struct ibv_spec_header {
45 enum ibv_flow_spec_type type;
50 * Discover the maximum number of priority available.
53 * Pointer to the Ethernet device structure.
56 * number of supported flow priority on success, a negative errno
57 * value otherwise and rte_errno is set.
60 mlx5_flow_discover_priorities(struct rte_eth_dev *dev)
62 struct mlx5_priv *priv = dev->data->dev_private;
64 struct ibv_flow_attr attr;
65 struct ibv_flow_spec_eth eth;
66 struct ibv_flow_spec_action_drop drop;
70 .port = (uint8_t)priv->dev_port,
73 .type = IBV_FLOW_SPEC_ETH,
74 .size = sizeof(struct ibv_flow_spec_eth),
77 .size = sizeof(struct ibv_flow_spec_action_drop),
78 .type = IBV_FLOW_SPEC_ACTION_DROP,
81 struct ibv_flow *flow;
82 struct mlx5_hrxq *drop = priv->drop_queue.hrxq;
83 uint16_t vprio[] = { 8, 16 };
91 for (i = 0; i != RTE_DIM(vprio); i++) {
92 flow_attr.attr.priority = vprio[i] - 1;
93 flow = mlx5_glue->create_flow(drop->qp, &flow_attr.attr);
96 claim_zero(mlx5_glue->destroy_flow(flow));
101 priority = RTE_DIM(priority_map_3);
104 priority = RTE_DIM(priority_map_5);
109 "port %u verbs maximum priority: %d expected 8/16",
110 dev->data->port_id, priority);
113 DRV_LOG(INFO, "port %u supported flow priorities:"
114 " 0-%d for ingress or egress root table,"
115 " 0-%d for non-root table or transfer root table.",
116 dev->data->port_id, priority - 2,
117 MLX5_NON_ROOT_FLOW_MAX_PRIO - 1);
122 * Adjust flow priority based on the highest layer and the request priority.
125 * Pointer to the Ethernet device structure.
126 * @param[in] priority
127 * The rule base priority.
128 * @param[in] subpriority
129 * The priority based on the items.
135 mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
136 uint32_t subpriority)
139 struct mlx5_priv *priv = dev->data->dev_private;
141 switch (priv->config.flow_prio) {
142 case RTE_DIM(priority_map_3):
143 res = priority_map_3[priority][subpriority];
145 case RTE_DIM(priority_map_5):
146 res = priority_map_5[priority][subpriority];
153 * Get Verbs flow counter by index.
156 * Pointer to the Ethernet device structure.
158 * mlx5 flow counter index in the container.
160 * mlx5 flow counter pool in the container,
163 * A pointer to the counter, NULL otherwise.
165 static struct mlx5_flow_counter *
166 flow_verbs_counter_get_by_idx(struct rte_eth_dev *dev,
168 struct mlx5_flow_counter_pool **ppool)
170 struct mlx5_priv *priv = dev->data->dev_private;
171 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
172 struct mlx5_flow_counter_pool *pool;
174 idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
175 pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
179 return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
183 * Create Verbs flow counter with Verbs library.
186 * Pointer to the Ethernet device structure.
187 * @param[in, out] counter
188 * mlx5 flow counter object, contains the counter id,
189 * handle of created Verbs flow counter is returned
190 * in cs field (if counters are supported).
193 * 0 On success else a negative errno value is returned
194 * and rte_errno is set.
197 flow_verbs_counter_create(struct rte_eth_dev *dev,
198 struct mlx5_flow_counter *counter)
200 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
201 struct mlx5_priv *priv = dev->data->dev_private;
202 struct ibv_context *ctx = priv->sh->ctx;
203 struct ibv_counter_set_init_attr init = {
204 .counter_set_id = counter->shared_info.id};
206 counter->dcs_when_free = mlx5_glue->create_counter_set(ctx, &init);
207 if (!counter->dcs_when_free) {
212 #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
213 struct mlx5_priv *priv = dev->data->dev_private;
214 struct ibv_context *ctx = priv->sh->ctx;
215 struct ibv_counters_init_attr init = {0};
216 struct ibv_counter_attach_attr attach;
219 memset(&attach, 0, sizeof(attach));
220 counter->dcs_when_free = mlx5_glue->create_counters(ctx, &init);
221 if (!counter->dcs_when_free) {
225 attach.counter_desc = IBV_COUNTER_PACKETS;
227 ret = mlx5_glue->attach_counters(counter->dcs_when_free, &attach, NULL);
229 attach.counter_desc = IBV_COUNTER_BYTES;
231 ret = mlx5_glue->attach_counters
232 (counter->dcs_when_free, &attach, NULL);
235 claim_zero(mlx5_glue->destroy_counters(counter->dcs_when_free));
236 counter->dcs_when_free = NULL;
250 * Get a flow counter.
253 * Pointer to the Ethernet device structure.
255 * Indicate if this counter is shared with other flows.
257 * Counter identifier.
260 * Index to the counter, 0 otherwise and rte_errno is set.
263 flow_verbs_counter_new(struct rte_eth_dev *dev, uint32_t shared, uint32_t id)
265 struct mlx5_priv *priv = dev->data->dev_private;
266 struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
267 struct mlx5_flow_counter_pool *pool = NULL;
268 struct mlx5_flow_counter *cnt = NULL;
269 union mlx5_l3t_data data;
270 uint32_t n_valid = cmng->n_valid;
271 uint32_t pool_idx, cnt_idx;
275 if (shared && !mlx5_l3t_get_entry(priv->sh->cnt_id_tbl, id, &data) &&
278 for (pool_idx = 0; pool_idx < n_valid; ++pool_idx) {
279 pool = cmng->pools[pool_idx];
282 cnt = TAILQ_FIRST(&pool->counters[0]);
287 struct mlx5_flow_counter_pool **pools;
290 if (n_valid == cmng->n) {
291 /* Resize the container pool array. */
292 size = sizeof(struct mlx5_flow_counter_pool *) *
293 (n_valid + MLX5_CNT_CONTAINER_RESIZE);
294 pools = mlx5_malloc(MLX5_MEM_ZERO, size, 0,
299 memcpy(pools, cmng->pools,
300 sizeof(struct mlx5_flow_counter_pool *) *
302 mlx5_free(cmng->pools);
305 cmng->n += MLX5_CNT_CONTAINER_RESIZE;
307 /* Allocate memory for new pool*/
308 size = sizeof(*pool) + sizeof(*cnt) * MLX5_COUNTERS_PER_POOL;
309 pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
312 for (i = 0; i < MLX5_COUNTERS_PER_POOL; ++i) {
313 cnt = MLX5_POOL_GET_CNT(pool, i);
314 TAILQ_INSERT_HEAD(&pool->counters[0], cnt, next);
316 cnt = MLX5_POOL_GET_CNT(pool, 0);
317 cmng->pools[n_valid] = pool;
321 TAILQ_REMOVE(&pool->counters[0], cnt, next);
322 i = MLX5_CNT_ARRAY_IDX(pool, cnt);
323 cnt_idx = MLX5_MAKE_CNT_IDX(pool_idx, i);
325 data.dword = cnt_idx;
326 if (mlx5_l3t_set_entry(priv->sh->cnt_id_tbl, id, &data))
328 cnt->shared_info.id = id;
329 cnt_idx |= MLX5_CNT_SHARED_OFFSET;
331 /* Create counter with Verbs. */
332 ret = flow_verbs_counter_create(dev, cnt);
334 cnt->dcs_when_active = cnt->dcs_when_free;
339 TAILQ_INSERT_HEAD(&pool->counters[0], cnt, next);
340 /* Some error occurred in Verbs library. */
346 * Release a flow counter.
349 * Pointer to the Ethernet device structure.
351 * Index to the counter handler.
354 flow_verbs_counter_release(struct rte_eth_dev *dev, uint32_t counter)
356 struct mlx5_priv *priv = dev->data->dev_private;
357 struct mlx5_flow_counter_pool *pool;
358 struct mlx5_flow_counter *cnt;
360 cnt = flow_verbs_counter_get_by_idx(dev, counter, &pool);
361 if (IS_SHARED_CNT(counter) &&
362 mlx5_l3t_clear_entry(priv->sh->cnt_id_tbl, cnt->shared_info.id))
364 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
365 claim_zero(mlx5_glue->destroy_counter_set
366 ((struct ibv_counter_set *)cnt->dcs_when_active));
367 #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
368 claim_zero(mlx5_glue->destroy_counters
369 ((struct ibv_counters *)cnt->dcs_when_active));
371 TAILQ_INSERT_HEAD(&pool->counters[0], cnt, next);
375 * Query a flow counter via Verbs library call.
377 * @see rte_flow_query()
381 flow_verbs_counter_query(struct rte_eth_dev *dev __rte_unused,
382 struct rte_flow *flow, void *data,
383 struct rte_flow_error *error)
385 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
386 defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
388 struct mlx5_flow_counter_pool *pool;
389 struct mlx5_flow_counter *cnt = flow_verbs_counter_get_by_idx
390 (dev, flow->counter, &pool);
391 struct rte_flow_query_count *qc = data;
392 uint64_t counters[2] = {0, 0};
393 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
394 struct ibv_query_counter_set_attr query_cs_attr = {
395 .dcs_when_free = (struct ibv_counter_set *)
396 cnt->dcs_when_active,
397 .query_flags = IBV_COUNTER_SET_FORCE_UPDATE,
399 struct ibv_counter_set_data query_out = {
401 .outlen = 2 * sizeof(uint64_t),
403 int err = mlx5_glue->query_counter_set(&query_cs_attr,
405 #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
406 int err = mlx5_glue->query_counters
407 ((struct ibv_counters *)cnt->dcs_when_active, counters,
409 IBV_READ_COUNTERS_ATTR_PREFER_CACHED);
412 return rte_flow_error_set
414 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
416 "cannot read counter");
419 qc->hits = counters[0] - cnt->hits;
420 qc->bytes = counters[1] - cnt->bytes;
422 cnt->hits = counters[0];
423 cnt->bytes = counters[1];
427 return rte_flow_error_set(error, EINVAL,
428 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
430 "flow does not have counter");
434 return rte_flow_error_set(error, ENOTSUP,
435 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
437 "counters are not available");
442 * Add a verbs item specification into @p verbs.
445 * Pointer to verbs structure.
447 * Create specification.
449 * Size in bytes of the specification to copy.
452 flow_verbs_spec_add(struct mlx5_flow_verbs_workspace *verbs,
453 void *src, unsigned int size)
459 MLX5_ASSERT(verbs->specs);
460 dst = (void *)(verbs->specs + verbs->size);
461 memcpy(dst, src, size);
462 ++verbs->attr.num_of_specs;
467 * Convert the @p item into a Verbs specification. This function assumes that
468 * the input is valid and that there is space to insert the requested item
471 * @param[in, out] dev_flow
472 * Pointer to dev_flow structure.
474 * Item specification.
475 * @param[in] item_flags
479 flow_verbs_translate_item_eth(struct mlx5_flow *dev_flow,
480 const struct rte_flow_item *item,
483 const struct rte_flow_item_eth *spec = item->spec;
484 const struct rte_flow_item_eth *mask = item->mask;
485 const unsigned int size = sizeof(struct ibv_flow_spec_eth);
486 struct ibv_flow_spec_eth eth = {
487 .type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags),
492 mask = &rte_flow_item_eth_mask;
496 memcpy(ð.val.dst_mac, spec->dst.addr_bytes,
498 memcpy(ð.val.src_mac, spec->src.addr_bytes,
500 eth.val.ether_type = spec->type;
501 memcpy(ð.mask.dst_mac, mask->dst.addr_bytes,
503 memcpy(ð.mask.src_mac, mask->src.addr_bytes,
505 eth.mask.ether_type = mask->type;
506 /* Remove unwanted bits from values. */
507 for (i = 0; i < RTE_ETHER_ADDR_LEN; ++i) {
508 eth.val.dst_mac[i] &= eth.mask.dst_mac[i];
509 eth.val.src_mac[i] &= eth.mask.src_mac[i];
511 eth.val.ether_type &= eth.mask.ether_type;
513 flow_verbs_spec_add(&dev_flow->verbs, ð, size);
517 * Update the VLAN tag in the Verbs Ethernet specification.
518 * This function assumes that the input is valid and there is space to add
519 * the requested item.
521 * @param[in, out] attr
522 * Pointer to Verbs attributes structure.
524 * Verbs structure containing the VLAN information to copy.
527 flow_verbs_item_vlan_update(struct ibv_flow_attr *attr,
528 struct ibv_flow_spec_eth *eth)
531 const enum ibv_flow_spec_type search = eth->type;
532 struct ibv_spec_header *hdr = (struct ibv_spec_header *)
533 ((uint8_t *)attr + sizeof(struct ibv_flow_attr));
535 for (i = 0; i != attr->num_of_specs; ++i) {
536 if (hdr->type == search) {
537 struct ibv_flow_spec_eth *e =
538 (struct ibv_flow_spec_eth *)hdr;
540 e->val.vlan_tag = eth->val.vlan_tag;
541 e->mask.vlan_tag = eth->mask.vlan_tag;
542 e->val.ether_type = eth->val.ether_type;
543 e->mask.ether_type = eth->mask.ether_type;
546 hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
551 * Convert the @p item into a Verbs specification. This function assumes that
552 * the input is valid and that there is space to insert the requested item
555 * @param[in, out] dev_flow
556 * Pointer to dev_flow structure.
558 * Item specification.
559 * @param[in] item_flags
563 flow_verbs_translate_item_vlan(struct mlx5_flow *dev_flow,
564 const struct rte_flow_item *item,
567 const struct rte_flow_item_vlan *spec = item->spec;
568 const struct rte_flow_item_vlan *mask = item->mask;
569 unsigned int size = sizeof(struct ibv_flow_spec_eth);
570 const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
571 struct ibv_flow_spec_eth eth = {
572 .type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags),
575 const uint32_t l2m = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
576 MLX5_FLOW_LAYER_OUTER_L2;
579 mask = &rte_flow_item_vlan_mask;
581 eth.val.vlan_tag = spec->tci;
582 eth.mask.vlan_tag = mask->tci;
583 eth.val.vlan_tag &= eth.mask.vlan_tag;
584 eth.val.ether_type = spec->inner_type;
585 eth.mask.ether_type = mask->inner_type;
586 eth.val.ether_type &= eth.mask.ether_type;
588 if (!(item_flags & l2m))
589 flow_verbs_spec_add(&dev_flow->verbs, ð, size);
591 flow_verbs_item_vlan_update(&dev_flow->verbs.attr, ð);
593 dev_flow->handle->vf_vlan.tag =
594 rte_be_to_cpu_16(spec->tci) & 0x0fff;
598 * Convert the @p item into a Verbs specification. This function assumes that
599 * the input is valid and that there is space to insert the requested item
602 * @param[in, out] dev_flow
603 * Pointer to dev_flow structure.
605 * Item specification.
606 * @param[in] item_flags
610 flow_verbs_translate_item_ipv4(struct mlx5_flow *dev_flow,
611 const struct rte_flow_item *item,
614 const struct rte_flow_item_ipv4 *spec = item->spec;
615 const struct rte_flow_item_ipv4 *mask = item->mask;
616 unsigned int size = sizeof(struct ibv_flow_spec_ipv4_ext);
617 struct ibv_flow_spec_ipv4_ext ipv4 = {
618 .type = IBV_FLOW_SPEC_IPV4_EXT | VERBS_SPEC_INNER(item_flags),
623 mask = &rte_flow_item_ipv4_mask;
625 ipv4.val = (struct ibv_flow_ipv4_ext_filter){
626 .src_ip = spec->hdr.src_addr,
627 .dst_ip = spec->hdr.dst_addr,
628 .proto = spec->hdr.next_proto_id,
629 .tos = spec->hdr.type_of_service,
631 ipv4.mask = (struct ibv_flow_ipv4_ext_filter){
632 .src_ip = mask->hdr.src_addr,
633 .dst_ip = mask->hdr.dst_addr,
634 .proto = mask->hdr.next_proto_id,
635 .tos = mask->hdr.type_of_service,
637 /* Remove unwanted bits from values. */
638 ipv4.val.src_ip &= ipv4.mask.src_ip;
639 ipv4.val.dst_ip &= ipv4.mask.dst_ip;
640 ipv4.val.proto &= ipv4.mask.proto;
641 ipv4.val.tos &= ipv4.mask.tos;
643 flow_verbs_spec_add(&dev_flow->verbs, &ipv4, size);
647 * Convert the @p item into a Verbs specification. This function assumes that
648 * the input is valid and that there is space to insert the requested item
651 * @param[in, out] dev_flow
652 * Pointer to dev_flow structure.
654 * Item specification.
655 * @param[in] item_flags
659 flow_verbs_translate_item_ipv6(struct mlx5_flow *dev_flow,
660 const struct rte_flow_item *item,
663 const struct rte_flow_item_ipv6 *spec = item->spec;
664 const struct rte_flow_item_ipv6 *mask = item->mask;
665 unsigned int size = sizeof(struct ibv_flow_spec_ipv6);
666 struct ibv_flow_spec_ipv6 ipv6 = {
667 .type = IBV_FLOW_SPEC_IPV6 | VERBS_SPEC_INNER(item_flags),
672 mask = &rte_flow_item_ipv6_mask;
675 uint32_t vtc_flow_val;
676 uint32_t vtc_flow_mask;
678 memcpy(&ipv6.val.src_ip, spec->hdr.src_addr,
679 RTE_DIM(ipv6.val.src_ip));
680 memcpy(&ipv6.val.dst_ip, spec->hdr.dst_addr,
681 RTE_DIM(ipv6.val.dst_ip));
682 memcpy(&ipv6.mask.src_ip, mask->hdr.src_addr,
683 RTE_DIM(ipv6.mask.src_ip));
684 memcpy(&ipv6.mask.dst_ip, mask->hdr.dst_addr,
685 RTE_DIM(ipv6.mask.dst_ip));
686 vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);
687 vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);
688 ipv6.val.flow_label =
689 rte_cpu_to_be_32((vtc_flow_val & RTE_IPV6_HDR_FL_MASK) >>
690 RTE_IPV6_HDR_FL_SHIFT);
691 ipv6.val.traffic_class = (vtc_flow_val & RTE_IPV6_HDR_TC_MASK) >>
692 RTE_IPV6_HDR_TC_SHIFT;
693 ipv6.val.next_hdr = spec->hdr.proto;
694 ipv6.mask.flow_label =
695 rte_cpu_to_be_32((vtc_flow_mask & RTE_IPV6_HDR_FL_MASK) >>
696 RTE_IPV6_HDR_FL_SHIFT);
697 ipv6.mask.traffic_class = (vtc_flow_mask & RTE_IPV6_HDR_TC_MASK) >>
698 RTE_IPV6_HDR_TC_SHIFT;
699 ipv6.mask.next_hdr = mask->hdr.proto;
700 /* Remove unwanted bits from values. */
701 for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {
702 ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];
703 ipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];
705 ipv6.val.flow_label &= ipv6.mask.flow_label;
706 ipv6.val.traffic_class &= ipv6.mask.traffic_class;
707 ipv6.val.next_hdr &= ipv6.mask.next_hdr;
709 flow_verbs_spec_add(&dev_flow->verbs, &ipv6, size);
713 * Convert the @p item into a Verbs specification. This function assumes that
714 * the input is valid and that there is space to insert the requested item
717 * @param[in, out] dev_flow
718 * Pointer to dev_flow structure.
720 * Item specification.
721 * @param[in] item_flags
725 flow_verbs_translate_item_tcp(struct mlx5_flow *dev_flow,
726 const struct rte_flow_item *item,
727 uint64_t item_flags __rte_unused)
729 const struct rte_flow_item_tcp *spec = item->spec;
730 const struct rte_flow_item_tcp *mask = item->mask;
731 unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
732 struct ibv_flow_spec_tcp_udp tcp = {
733 .type = IBV_FLOW_SPEC_TCP | VERBS_SPEC_INNER(item_flags),
738 mask = &rte_flow_item_tcp_mask;
740 tcp.val.dst_port = spec->hdr.dst_port;
741 tcp.val.src_port = spec->hdr.src_port;
742 tcp.mask.dst_port = mask->hdr.dst_port;
743 tcp.mask.src_port = mask->hdr.src_port;
744 /* Remove unwanted bits from values. */
745 tcp.val.src_port &= tcp.mask.src_port;
746 tcp.val.dst_port &= tcp.mask.dst_port;
748 flow_verbs_spec_add(&dev_flow->verbs, &tcp, size);
752 * Convert the @p item into a Verbs specification. This function assumes that
753 * the input is valid and that there is space to insert the requested item
756 * @param[in, out] dev_flow
757 * Pointer to dev_flow structure.
759 * Item specification.
760 * @param[in] item_flags
764 flow_verbs_translate_item_udp(struct mlx5_flow *dev_flow,
765 const struct rte_flow_item *item,
766 uint64_t item_flags __rte_unused)
768 const struct rte_flow_item_udp *spec = item->spec;
769 const struct rte_flow_item_udp *mask = item->mask;
770 unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
771 struct ibv_flow_spec_tcp_udp udp = {
772 .type = IBV_FLOW_SPEC_UDP | VERBS_SPEC_INNER(item_flags),
777 mask = &rte_flow_item_udp_mask;
779 udp.val.dst_port = spec->hdr.dst_port;
780 udp.val.src_port = spec->hdr.src_port;
781 udp.mask.dst_port = mask->hdr.dst_port;
782 udp.mask.src_port = mask->hdr.src_port;
783 /* Remove unwanted bits from values. */
784 udp.val.src_port &= udp.mask.src_port;
785 udp.val.dst_port &= udp.mask.dst_port;
788 while (item->type == RTE_FLOW_ITEM_TYPE_VOID)
790 if (!(udp.val.dst_port & udp.mask.dst_port)) {
791 switch ((item)->type) {
792 case RTE_FLOW_ITEM_TYPE_VXLAN:
793 udp.val.dst_port = htons(MLX5_UDP_PORT_VXLAN);
794 udp.mask.dst_port = 0xffff;
796 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
797 udp.val.dst_port = htons(MLX5_UDP_PORT_VXLAN_GPE);
798 udp.mask.dst_port = 0xffff;
800 case RTE_FLOW_ITEM_TYPE_MPLS:
801 udp.val.dst_port = htons(MLX5_UDP_PORT_MPLS);
802 udp.mask.dst_port = 0xffff;
809 flow_verbs_spec_add(&dev_flow->verbs, &udp, size);
813 * Convert the @p item into a Verbs specification. This function assumes that
814 * the input is valid and that there is space to insert the requested item
817 * @param[in, out] dev_flow
818 * Pointer to dev_flow structure.
820 * Item specification.
821 * @param[in] item_flags
825 flow_verbs_translate_item_vxlan(struct mlx5_flow *dev_flow,
826 const struct rte_flow_item *item,
827 uint64_t item_flags __rte_unused)
829 const struct rte_flow_item_vxlan *spec = item->spec;
830 const struct rte_flow_item_vxlan *mask = item->mask;
831 unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
832 struct ibv_flow_spec_tunnel vxlan = {
833 .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
839 } id = { .vlan_id = 0, };
842 mask = &rte_flow_item_vxlan_mask;
844 memcpy(&id.vni[1], spec->vni, 3);
845 vxlan.val.tunnel_id = id.vlan_id;
846 memcpy(&id.vni[1], mask->vni, 3);
847 vxlan.mask.tunnel_id = id.vlan_id;
848 /* Remove unwanted bits from values. */
849 vxlan.val.tunnel_id &= vxlan.mask.tunnel_id;
851 flow_verbs_spec_add(&dev_flow->verbs, &vxlan, size);
855 * Convert the @p item into a Verbs specification. This function assumes that
856 * the input is valid and that there is space to insert the requested item
859 * @param[in, out] dev_flow
860 * Pointer to dev_flow structure.
862 * Item specification.
863 * @param[in] item_flags
867 flow_verbs_translate_item_vxlan_gpe(struct mlx5_flow *dev_flow,
868 const struct rte_flow_item *item,
869 uint64_t item_flags __rte_unused)
871 const struct rte_flow_item_vxlan_gpe *spec = item->spec;
872 const struct rte_flow_item_vxlan_gpe *mask = item->mask;
873 unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
874 struct ibv_flow_spec_tunnel vxlan_gpe = {
875 .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
881 } id = { .vlan_id = 0, };
884 mask = &rte_flow_item_vxlan_gpe_mask;
886 memcpy(&id.vni[1], spec->vni, 3);
887 vxlan_gpe.val.tunnel_id = id.vlan_id;
888 memcpy(&id.vni[1], mask->vni, 3);
889 vxlan_gpe.mask.tunnel_id = id.vlan_id;
890 /* Remove unwanted bits from values. */
891 vxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id;
893 flow_verbs_spec_add(&dev_flow->verbs, &vxlan_gpe, size);
897 * Update the protocol in Verbs IPv4/IPv6 spec.
899 * @param[in, out] attr
900 * Pointer to Verbs attributes structure.
902 * Specification type to search in order to update the IP protocol.
903 * @param[in] protocol
904 * Protocol value to set if none is present in the specification.
907 flow_verbs_item_gre_ip_protocol_update(struct ibv_flow_attr *attr,
908 enum ibv_flow_spec_type search,
912 struct ibv_spec_header *hdr = (struct ibv_spec_header *)
913 ((uint8_t *)attr + sizeof(struct ibv_flow_attr));
917 for (i = 0; i != attr->num_of_specs; ++i) {
918 if (hdr->type == search) {
920 struct ibv_flow_spec_ipv4_ext *ipv4;
921 struct ibv_flow_spec_ipv6 *ipv6;
925 case IBV_FLOW_SPEC_IPV4_EXT:
926 ip.ipv4 = (struct ibv_flow_spec_ipv4_ext *)hdr;
927 if (!ip.ipv4->val.proto) {
928 ip.ipv4->val.proto = protocol;
929 ip.ipv4->mask.proto = 0xff;
932 case IBV_FLOW_SPEC_IPV6:
933 ip.ipv6 = (struct ibv_flow_spec_ipv6 *)hdr;
934 if (!ip.ipv6->val.next_hdr) {
935 ip.ipv6->val.next_hdr = protocol;
936 ip.ipv6->mask.next_hdr = 0xff;
944 hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
949 * Convert the @p item into a Verbs specification. This function assumes that
950 * the input is valid and that there is space to insert the requested item
953 * @param[in, out] dev_flow
954 * Pointer to dev_flow structure.
956 * Item specification.
957 * @param[in] item_flags
961 flow_verbs_translate_item_gre(struct mlx5_flow *dev_flow,
962 const struct rte_flow_item *item __rte_unused,
965 struct mlx5_flow_verbs_workspace *verbs = &dev_flow->verbs;
966 #ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT
967 unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
968 struct ibv_flow_spec_tunnel tunnel = {
969 .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
973 const struct rte_flow_item_gre *spec = item->spec;
974 const struct rte_flow_item_gre *mask = item->mask;
975 unsigned int size = sizeof(struct ibv_flow_spec_gre);
976 struct ibv_flow_spec_gre tunnel = {
977 .type = IBV_FLOW_SPEC_GRE,
982 mask = &rte_flow_item_gre_mask;
984 tunnel.val.c_ks_res0_ver = spec->c_rsvd0_ver;
985 tunnel.val.protocol = spec->protocol;
986 tunnel.mask.c_ks_res0_ver = mask->c_rsvd0_ver;
987 tunnel.mask.protocol = mask->protocol;
988 /* Remove unwanted bits from values. */
989 tunnel.val.c_ks_res0_ver &= tunnel.mask.c_ks_res0_ver;
990 tunnel.val.protocol &= tunnel.mask.protocol;
991 tunnel.val.key &= tunnel.mask.key;
994 if (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
995 flow_verbs_item_gre_ip_protocol_update(&verbs->attr,
996 IBV_FLOW_SPEC_IPV4_EXT,
999 flow_verbs_item_gre_ip_protocol_update(&verbs->attr,
1002 flow_verbs_spec_add(verbs, &tunnel, size);
1006 * Convert the @p action into a Verbs specification. This function assumes that
1007 * the input is valid and that there is space to insert the requested action
1008 * into the flow. This function also return the action that was added.
1010 * @param[in, out] dev_flow
1011 * Pointer to dev_flow structure.
1013 * Item specification.
1014 * @param[in] item_flags
1015 * Parsed item flags.
1018 flow_verbs_translate_item_mpls(struct mlx5_flow *dev_flow __rte_unused,
1019 const struct rte_flow_item *item __rte_unused,
1020 uint64_t item_flags __rte_unused)
1022 #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
1023 const struct rte_flow_item_mpls *spec = item->spec;
1024 const struct rte_flow_item_mpls *mask = item->mask;
1025 unsigned int size = sizeof(struct ibv_flow_spec_mpls);
1026 struct ibv_flow_spec_mpls mpls = {
1027 .type = IBV_FLOW_SPEC_MPLS,
1032 mask = &rte_flow_item_mpls_mask;
1034 memcpy(&mpls.val.label, spec, sizeof(mpls.val.label));
1035 memcpy(&mpls.mask.label, mask, sizeof(mpls.mask.label));
1036 /* Remove unwanted bits from values. */
1037 mpls.val.label &= mpls.mask.label;
1039 flow_verbs_spec_add(&dev_flow->verbs, &mpls, size);
1044 * Convert the @p action into a Verbs specification. This function assumes that
1045 * the input is valid and that there is space to insert the requested action
1048 * @param[in] dev_flow
1049 * Pointer to mlx5_flow.
1051 * Action configuration.
1054 flow_verbs_translate_action_drop
1055 (struct mlx5_flow *dev_flow,
1056 const struct rte_flow_action *action __rte_unused)
1058 unsigned int size = sizeof(struct ibv_flow_spec_action_drop);
1059 struct ibv_flow_spec_action_drop drop = {
1060 .type = IBV_FLOW_SPEC_ACTION_DROP,
1064 flow_verbs_spec_add(&dev_flow->verbs, &drop, size);
1068 * Convert the @p action into a Verbs specification. This function assumes that
1069 * the input is valid and that there is space to insert the requested action
1072 * @param[in] rss_desc
1073 * Pointer to mlx5_flow_rss_desc.
1075 * Action configuration.
1078 flow_verbs_translate_action_queue(struct mlx5_flow_rss_desc *rss_desc,
1079 const struct rte_flow_action *action)
1081 const struct rte_flow_action_queue *queue = action->conf;
1083 rss_desc->queue[0] = queue->index;
1084 rss_desc->queue_num = 1;
1088 * Convert the @p action into a Verbs specification. This function assumes that
1089 * the input is valid and that there is space to insert the requested action
1092 * @param[in] rss_desc
1093 * Pointer to mlx5_flow_rss_desc.
1095 * Action configuration.
1098 flow_verbs_translate_action_rss(struct mlx5_flow_rss_desc *rss_desc,
1099 const struct rte_flow_action *action)
1101 const struct rte_flow_action_rss *rss = action->conf;
1102 const uint8_t *rss_key;
1104 memcpy(rss_desc->queue, rss->queue, rss->queue_num * sizeof(uint16_t));
1105 rss_desc->queue_num = rss->queue_num;
1106 /* NULL RSS key indicates default RSS key. */
1107 rss_key = !rss->key ? rss_hash_default_key : rss->key;
1108 memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
1110 * rss->level and rss.types should be set in advance when expanding
1116 * Convert the @p action into a Verbs specification. This function assumes that
1117 * the input is valid and that there is space to insert the requested action
1120 * @param[in] dev_flow
1121 * Pointer to mlx5_flow.
1123 * Action configuration.
1126 flow_verbs_translate_action_flag
1127 (struct mlx5_flow *dev_flow,
1128 const struct rte_flow_action *action __rte_unused)
1130 unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
1131 struct ibv_flow_spec_action_tag tag = {
1132 .type = IBV_FLOW_SPEC_ACTION_TAG,
1134 .tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT),
1137 flow_verbs_spec_add(&dev_flow->verbs, &tag, size);
1141 * Convert the @p action into a Verbs specification. This function assumes that
1142 * the input is valid and that there is space to insert the requested action
1145 * @param[in] dev_flow
1146 * Pointer to mlx5_flow.
1148 * Action configuration.
1151 flow_verbs_translate_action_mark(struct mlx5_flow *dev_flow,
1152 const struct rte_flow_action *action)
1154 const struct rte_flow_action_mark *mark = action->conf;
1155 unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
1156 struct ibv_flow_spec_action_tag tag = {
1157 .type = IBV_FLOW_SPEC_ACTION_TAG,
1159 .tag_id = mlx5_flow_mark_set(mark->id),
1162 flow_verbs_spec_add(&dev_flow->verbs, &tag, size);
1166 * Convert the @p action into a Verbs specification. This function assumes that
1167 * the input is valid and that there is space to insert the requested action
1171 * Pointer to the Ethernet device structure.
1173 * Action configuration.
1174 * @param[in] dev_flow
1175 * Pointer to mlx5_flow.
1177 * Pointer to error structure.
1180 * 0 On success else a negative errno value is returned and rte_errno is set.
1183 flow_verbs_translate_action_count(struct mlx5_flow *dev_flow,
1184 const struct rte_flow_action *action,
1185 struct rte_eth_dev *dev,
1186 struct rte_flow_error *error)
1188 const struct rte_flow_action_count *count = action->conf;
1189 struct rte_flow *flow = dev_flow->flow;
1190 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
1191 defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
1192 struct mlx5_flow_counter_pool *pool;
1193 struct mlx5_flow_counter *cnt = NULL;
1194 unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
1195 struct ibv_flow_spec_counter_action counter = {
1196 .type = IBV_FLOW_SPEC_ACTION_COUNT,
1201 if (!flow->counter) {
1202 flow->counter = flow_verbs_counter_new(dev, count->shared,
1205 return rte_flow_error_set(error, rte_errno,
1206 RTE_FLOW_ERROR_TYPE_ACTION,
1208 "cannot get counter"
1211 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
1212 cnt = flow_verbs_counter_get_by_idx(dev, flow->counter, &pool);
1213 counter.counter_set_handle =
1214 ((struct ibv_counter_set *)cnt->dcs_when_active)->handle;
1215 flow_verbs_spec_add(&dev_flow->verbs, &counter, size);
1216 #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
1217 cnt = flow_verbs_counter_get_by_idx(dev, flow->counter, &pool);
1218 counter.counters = (struct ibv_counters *)cnt->dcs_when_active;
1219 flow_verbs_spec_add(&dev_flow->verbs, &counter, size);
1225 * Internal validation function. For validating both actions and items.
1228 * Pointer to the Ethernet device structure.
1230 * Pointer to the flow attributes.
1232 * Pointer to the list of items.
1233 * @param[in] actions
1234 * Pointer to the list of actions.
1235 * @param[in] external
1236 * This flow rule is created by request external to PMD.
1237 * @param[in] hairpin
1238 * Number of hairpin TX actions, 0 means classic flow.
1240 * Pointer to the error structure.
1243 * 0 on success, a negative errno value otherwise and rte_errno is set.
1246 flow_verbs_validate(struct rte_eth_dev *dev,
1247 const struct rte_flow_attr *attr,
1248 const struct rte_flow_item items[],
1249 const struct rte_flow_action actions[],
1250 bool external __rte_unused,
1251 int hairpin __rte_unused,
1252 struct rte_flow_error *error)
1255 uint64_t action_flags = 0;
1256 uint64_t item_flags = 0;
1257 uint64_t last_item = 0;
1258 uint8_t next_protocol = 0xff;
1259 uint16_t ether_type = 0;
1260 bool is_empty_vlan = false;
1264 ret = mlx5_flow_validate_attributes(dev, attr, error);
1267 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1268 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
1271 switch (items->type) {
1272 case RTE_FLOW_ITEM_TYPE_VOID:
1274 case RTE_FLOW_ITEM_TYPE_ETH:
1275 ret = mlx5_flow_validate_item_eth(items, item_flags,
1279 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
1280 MLX5_FLOW_LAYER_OUTER_L2;
1281 if (items->mask != NULL && items->spec != NULL) {
1283 ((const struct rte_flow_item_eth *)
1286 ((const struct rte_flow_item_eth *)
1288 if (ether_type == RTE_BE16(RTE_ETHER_TYPE_VLAN))
1289 is_empty_vlan = true;
1290 ether_type = rte_be_to_cpu_16(ether_type);
1295 case RTE_FLOW_ITEM_TYPE_VLAN:
1296 ret = mlx5_flow_validate_item_vlan(items, item_flags,
1300 last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
1301 MLX5_FLOW_LAYER_INNER_VLAN) :
1302 (MLX5_FLOW_LAYER_OUTER_L2 |
1303 MLX5_FLOW_LAYER_OUTER_VLAN);
1304 if (items->mask != NULL && items->spec != NULL) {
1306 ((const struct rte_flow_item_vlan *)
1307 items->spec)->inner_type;
1309 ((const struct rte_flow_item_vlan *)
1310 items->mask)->inner_type;
1311 ether_type = rte_be_to_cpu_16(ether_type);
1315 is_empty_vlan = false;
1317 case RTE_FLOW_ITEM_TYPE_IPV4:
1318 ret = mlx5_flow_validate_item_ipv4
1320 last_item, ether_type, NULL,
1321 MLX5_ITEM_RANGE_NOT_ACCEPTED,
1325 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
1326 MLX5_FLOW_LAYER_OUTER_L3_IPV4;
1327 if (items->mask != NULL &&
1328 ((const struct rte_flow_item_ipv4 *)
1329 items->mask)->hdr.next_proto_id) {
1331 ((const struct rte_flow_item_ipv4 *)
1332 (items->spec))->hdr.next_proto_id;
1334 ((const struct rte_flow_item_ipv4 *)
1335 (items->mask))->hdr.next_proto_id;
1337 /* Reset for inner layer. */
1338 next_protocol = 0xff;
1341 case RTE_FLOW_ITEM_TYPE_IPV6:
1342 ret = mlx5_flow_validate_item_ipv6(items, item_flags,
1348 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
1349 MLX5_FLOW_LAYER_OUTER_L3_IPV6;
1350 if (items->mask != NULL &&
1351 ((const struct rte_flow_item_ipv6 *)
1352 items->mask)->hdr.proto) {
1354 ((const struct rte_flow_item_ipv6 *)
1355 items->spec)->hdr.proto;
1357 ((const struct rte_flow_item_ipv6 *)
1358 items->mask)->hdr.proto;
1360 /* Reset for inner layer. */
1361 next_protocol = 0xff;
1364 case RTE_FLOW_ITEM_TYPE_UDP:
1365 ret = mlx5_flow_validate_item_udp(items, item_flags,
1370 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
1371 MLX5_FLOW_LAYER_OUTER_L4_UDP;
1373 case RTE_FLOW_ITEM_TYPE_TCP:
1374 ret = mlx5_flow_validate_item_tcp
1377 &rte_flow_item_tcp_mask,
1381 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
1382 MLX5_FLOW_LAYER_OUTER_L4_TCP;
1384 case RTE_FLOW_ITEM_TYPE_VXLAN:
1385 ret = mlx5_flow_validate_item_vxlan(items, item_flags,
1389 last_item = MLX5_FLOW_LAYER_VXLAN;
1391 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1392 ret = mlx5_flow_validate_item_vxlan_gpe(items,
1397 last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
1399 case RTE_FLOW_ITEM_TYPE_GRE:
1400 ret = mlx5_flow_validate_item_gre(items, item_flags,
1401 next_protocol, error);
1404 last_item = MLX5_FLOW_LAYER_GRE;
1406 case RTE_FLOW_ITEM_TYPE_MPLS:
1407 ret = mlx5_flow_validate_item_mpls(dev, items,
1412 last_item = MLX5_FLOW_LAYER_MPLS;
1414 case RTE_FLOW_ITEM_TYPE_ICMP:
1415 case RTE_FLOW_ITEM_TYPE_ICMP6:
1416 return rte_flow_error_set(error, ENOTSUP,
1417 RTE_FLOW_ERROR_TYPE_ITEM,
1419 "item not supported");
1421 return rte_flow_error_set(error, ENOTSUP,
1422 RTE_FLOW_ERROR_TYPE_ITEM,
1423 NULL, "item not supported");
1425 item_flags |= last_item;
1428 return rte_flow_error_set(error, ENOTSUP,
1429 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1430 "VLAN matching without vid specification is not supported");
1431 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1432 switch (actions->type) {
1433 case RTE_FLOW_ACTION_TYPE_VOID:
1435 case RTE_FLOW_ACTION_TYPE_FLAG:
1436 ret = mlx5_flow_validate_action_flag(action_flags,
1441 action_flags |= MLX5_FLOW_ACTION_FLAG;
1443 case RTE_FLOW_ACTION_TYPE_MARK:
1444 ret = mlx5_flow_validate_action_mark(actions,
1450 action_flags |= MLX5_FLOW_ACTION_MARK;
1452 case RTE_FLOW_ACTION_TYPE_DROP:
1453 ret = mlx5_flow_validate_action_drop(action_flags,
1458 action_flags |= MLX5_FLOW_ACTION_DROP;
1460 case RTE_FLOW_ACTION_TYPE_QUEUE:
1461 ret = mlx5_flow_validate_action_queue(actions,
1467 action_flags |= MLX5_FLOW_ACTION_QUEUE;
1469 case RTE_FLOW_ACTION_TYPE_RSS:
1470 ret = mlx5_flow_validate_action_rss(actions,
1476 action_flags |= MLX5_FLOW_ACTION_RSS;
1478 case RTE_FLOW_ACTION_TYPE_COUNT:
1479 ret = mlx5_flow_validate_action_count(dev, attr, error);
1482 action_flags |= MLX5_FLOW_ACTION_COUNT;
1485 return rte_flow_error_set(error, ENOTSUP,
1486 RTE_FLOW_ERROR_TYPE_ACTION,
1488 "action not supported");
1492 * Validate the drop action mutual exclusion with other actions.
1493 * Drop action is mutually-exclusive with any other action, except for
1496 if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
1497 (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT)))
1498 return rte_flow_error_set(error, EINVAL,
1499 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1500 "Drop action is mutually-exclusive "
1501 "with any other action, except for "
1503 if (!(action_flags & MLX5_FLOW_FATE_ACTIONS))
1504 return rte_flow_error_set(error, EINVAL,
1505 RTE_FLOW_ERROR_TYPE_ACTION, actions,
1506 "no fate action is found");
1511 * Calculate the required bytes that are needed for the action part of the verbs
1514 * @param[in] actions
1515 * Pointer to the list of actions.
1518 * The size of the memory needed for all actions.
1521 flow_verbs_get_actions_size(const struct rte_flow_action actions[])
1525 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1526 switch (actions->type) {
1527 case RTE_FLOW_ACTION_TYPE_VOID:
1529 case RTE_FLOW_ACTION_TYPE_FLAG:
1530 size += sizeof(struct ibv_flow_spec_action_tag);
1532 case RTE_FLOW_ACTION_TYPE_MARK:
1533 size += sizeof(struct ibv_flow_spec_action_tag);
1535 case RTE_FLOW_ACTION_TYPE_DROP:
1536 size += sizeof(struct ibv_flow_spec_action_drop);
1538 case RTE_FLOW_ACTION_TYPE_QUEUE:
1540 case RTE_FLOW_ACTION_TYPE_RSS:
1542 case RTE_FLOW_ACTION_TYPE_COUNT:
1543 #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
1544 defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
1545 size += sizeof(struct ibv_flow_spec_counter_action);
1556 * Calculate the required bytes that are needed for the item part of the verbs
1560 * Pointer to the list of items.
1563 * The size of the memory needed for all items.
1566 flow_verbs_get_items_size(const struct rte_flow_item items[])
1570 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1571 switch (items->type) {
1572 case RTE_FLOW_ITEM_TYPE_VOID:
1574 case RTE_FLOW_ITEM_TYPE_ETH:
1575 size += sizeof(struct ibv_flow_spec_eth);
1577 case RTE_FLOW_ITEM_TYPE_VLAN:
1578 size += sizeof(struct ibv_flow_spec_eth);
1580 case RTE_FLOW_ITEM_TYPE_IPV4:
1581 size += sizeof(struct ibv_flow_spec_ipv4_ext);
1583 case RTE_FLOW_ITEM_TYPE_IPV6:
1584 size += sizeof(struct ibv_flow_spec_ipv6);
1586 case RTE_FLOW_ITEM_TYPE_UDP:
1587 size += sizeof(struct ibv_flow_spec_tcp_udp);
1589 case RTE_FLOW_ITEM_TYPE_TCP:
1590 size += sizeof(struct ibv_flow_spec_tcp_udp);
1592 case RTE_FLOW_ITEM_TYPE_VXLAN:
1593 size += sizeof(struct ibv_flow_spec_tunnel);
1595 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1596 size += sizeof(struct ibv_flow_spec_tunnel);
1598 #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
1599 case RTE_FLOW_ITEM_TYPE_GRE:
1600 size += sizeof(struct ibv_flow_spec_gre);
1602 case RTE_FLOW_ITEM_TYPE_MPLS:
1603 size += sizeof(struct ibv_flow_spec_mpls);
1606 case RTE_FLOW_ITEM_TYPE_GRE:
1607 size += sizeof(struct ibv_flow_spec_tunnel);
1618 * Internal preparation function. Allocate mlx5_flow with the required size.
1619 * The required size is calculate based on the actions and items. This function
1620 * also returns the detected actions and items for later use.
1623 * Pointer to Ethernet device.
1625 * Pointer to the flow attributes.
1627 * Pointer to the list of items.
1628 * @param[in] actions
1629 * Pointer to the list of actions.
1631 * Pointer to the error structure.
1634 * Pointer to mlx5_flow object on success, otherwise NULL and rte_errno
1637 static struct mlx5_flow *
1638 flow_verbs_prepare(struct rte_eth_dev *dev,
1639 const struct rte_flow_attr *attr __rte_unused,
1640 const struct rte_flow_item items[],
1641 const struct rte_flow_action actions[],
1642 struct rte_flow_error *error)
1645 uint32_t handle_idx = 0;
1646 struct mlx5_flow *dev_flow;
1647 struct mlx5_flow_handle *dev_handle;
1648 struct mlx5_priv *priv = dev->data->dev_private;
1649 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
1652 size += flow_verbs_get_actions_size(actions);
1653 size += flow_verbs_get_items_size(items);
1654 if (size > MLX5_VERBS_MAX_SPEC_ACT_SIZE) {
1655 rte_flow_error_set(error, E2BIG,
1656 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1657 "Verbs spec/action size too large");
1660 /* In case of corrupting the memory. */
1661 if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
1662 rte_flow_error_set(error, ENOSPC,
1663 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1664 "not free temporary device flow");
1667 dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
1670 rte_flow_error_set(error, ENOMEM,
1671 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1672 "not enough memory to create flow handle");
1675 MLX5_ASSERT(wks->flow_idx + 1 < RTE_DIM(wks->flows));
1676 dev_flow = &wks->flows[wks->flow_idx++];
1677 dev_flow->handle = dev_handle;
1678 dev_flow->handle_idx = handle_idx;
1679 /* Memcpy is used, only size needs to be cleared to 0. */
1680 dev_flow->verbs.size = 0;
1681 dev_flow->verbs.attr.num_of_specs = 0;
1682 dev_flow->ingress = attr->ingress;
1683 dev_flow->hash_fields = 0;
1684 /* Need to set transfer attribute: not supported in Verbs mode. */
1689 * Fill the flow with verb spec.
1692 * Pointer to Ethernet device.
1693 * @param[in, out] dev_flow
1694 * Pointer to the mlx5 flow.
1696 * Pointer to the flow attributes.
1698 * Pointer to the list of items.
1699 * @param[in] actions
1700 * Pointer to the list of actions.
1702 * Pointer to the error structure.
1705 * 0 on success, else a negative errno value otherwise and rte_errno is set.
1708 flow_verbs_translate(struct rte_eth_dev *dev,
1709 struct mlx5_flow *dev_flow,
1710 const struct rte_flow_attr *attr,
1711 const struct rte_flow_item items[],
1712 const struct rte_flow_action actions[],
1713 struct rte_flow_error *error)
1715 uint64_t item_flags = 0;
1716 uint64_t action_flags = 0;
1717 uint64_t priority = attr->priority;
1718 uint32_t subpriority = 0;
1719 struct mlx5_priv *priv = dev->data->dev_private;
1720 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
1721 struct mlx5_flow_rss_desc *rss_desc;
1724 rss_desc = &wks->rss_desc;
1725 if (priority == MLX5_FLOW_LOWEST_PRIO_INDICATOR)
1726 priority = priv->config.flow_prio - 1;
1727 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1730 switch (actions->type) {
1731 case RTE_FLOW_ACTION_TYPE_VOID:
1733 case RTE_FLOW_ACTION_TYPE_FLAG:
1734 flow_verbs_translate_action_flag(dev_flow, actions);
1735 action_flags |= MLX5_FLOW_ACTION_FLAG;
1736 dev_flow->handle->mark = 1;
1738 case RTE_FLOW_ACTION_TYPE_MARK:
1739 flow_verbs_translate_action_mark(dev_flow, actions);
1740 action_flags |= MLX5_FLOW_ACTION_MARK;
1741 dev_flow->handle->mark = 1;
1743 case RTE_FLOW_ACTION_TYPE_DROP:
1744 flow_verbs_translate_action_drop(dev_flow, actions);
1745 action_flags |= MLX5_FLOW_ACTION_DROP;
1746 dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
1748 case RTE_FLOW_ACTION_TYPE_QUEUE:
1749 flow_verbs_translate_action_queue(rss_desc, actions);
1750 action_flags |= MLX5_FLOW_ACTION_QUEUE;
1751 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
1753 case RTE_FLOW_ACTION_TYPE_RSS:
1754 flow_verbs_translate_action_rss(rss_desc, actions);
1755 action_flags |= MLX5_FLOW_ACTION_RSS;
1756 dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
1758 case RTE_FLOW_ACTION_TYPE_COUNT:
1759 ret = flow_verbs_translate_action_count(dev_flow,
1764 action_flags |= MLX5_FLOW_ACTION_COUNT;
1767 return rte_flow_error_set(error, ENOTSUP,
1768 RTE_FLOW_ERROR_TYPE_ACTION,
1770 "action not supported");
1773 dev_flow->act_flags = action_flags;
1774 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1775 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
1777 switch (items->type) {
1778 case RTE_FLOW_ITEM_TYPE_VOID:
1780 case RTE_FLOW_ITEM_TYPE_ETH:
1781 flow_verbs_translate_item_eth(dev_flow, items,
1783 subpriority = MLX5_PRIORITY_MAP_L2;
1784 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
1785 MLX5_FLOW_LAYER_OUTER_L2;
1787 case RTE_FLOW_ITEM_TYPE_VLAN:
1788 flow_verbs_translate_item_vlan(dev_flow, items,
1790 subpriority = MLX5_PRIORITY_MAP_L2;
1791 item_flags |= tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
1792 MLX5_FLOW_LAYER_INNER_VLAN) :
1793 (MLX5_FLOW_LAYER_OUTER_L2 |
1794 MLX5_FLOW_LAYER_OUTER_VLAN);
1796 case RTE_FLOW_ITEM_TYPE_IPV4:
1797 flow_verbs_translate_item_ipv4(dev_flow, items,
1799 subpriority = MLX5_PRIORITY_MAP_L3;
1800 dev_flow->hash_fields |=
1801 mlx5_flow_hashfields_adjust
1803 MLX5_IPV4_LAYER_TYPES,
1804 MLX5_IPV4_IBV_RX_HASH);
1805 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
1806 MLX5_FLOW_LAYER_OUTER_L3_IPV4;
1808 case RTE_FLOW_ITEM_TYPE_IPV6:
1809 flow_verbs_translate_item_ipv6(dev_flow, items,
1811 subpriority = MLX5_PRIORITY_MAP_L3;
1812 dev_flow->hash_fields |=
1813 mlx5_flow_hashfields_adjust
1815 MLX5_IPV6_LAYER_TYPES,
1816 MLX5_IPV6_IBV_RX_HASH);
1817 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
1818 MLX5_FLOW_LAYER_OUTER_L3_IPV6;
1820 case RTE_FLOW_ITEM_TYPE_TCP:
1821 flow_verbs_translate_item_tcp(dev_flow, items,
1823 subpriority = MLX5_PRIORITY_MAP_L4;
1824 dev_flow->hash_fields |=
1825 mlx5_flow_hashfields_adjust
1826 (rss_desc, tunnel, ETH_RSS_TCP,
1827 (IBV_RX_HASH_SRC_PORT_TCP |
1828 IBV_RX_HASH_DST_PORT_TCP));
1829 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
1830 MLX5_FLOW_LAYER_OUTER_L4_TCP;
1832 case RTE_FLOW_ITEM_TYPE_UDP:
1833 flow_verbs_translate_item_udp(dev_flow, items,
1835 subpriority = MLX5_PRIORITY_MAP_L4;
1836 dev_flow->hash_fields |=
1837 mlx5_flow_hashfields_adjust
1838 (rss_desc, tunnel, ETH_RSS_UDP,
1839 (IBV_RX_HASH_SRC_PORT_UDP |
1840 IBV_RX_HASH_DST_PORT_UDP));
1841 item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
1842 MLX5_FLOW_LAYER_OUTER_L4_UDP;
1844 case RTE_FLOW_ITEM_TYPE_VXLAN:
1845 flow_verbs_translate_item_vxlan(dev_flow, items,
1847 subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
1848 item_flags |= MLX5_FLOW_LAYER_VXLAN;
1850 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1851 flow_verbs_translate_item_vxlan_gpe(dev_flow, items,
1853 subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
1854 item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE;
1856 case RTE_FLOW_ITEM_TYPE_GRE:
1857 flow_verbs_translate_item_gre(dev_flow, items,
1859 subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
1860 item_flags |= MLX5_FLOW_LAYER_GRE;
1862 case RTE_FLOW_ITEM_TYPE_MPLS:
1863 flow_verbs_translate_item_mpls(dev_flow, items,
1865 subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
1866 item_flags |= MLX5_FLOW_LAYER_MPLS;
1869 return rte_flow_error_set(error, ENOTSUP,
1870 RTE_FLOW_ERROR_TYPE_ITEM,
1871 NULL, "item not supported");
1874 dev_flow->handle->layers = item_flags;
1875 /* Other members of attr will be ignored. */
1876 dev_flow->verbs.attr.priority =
1877 mlx5_flow_adjust_priority(dev, priority, subpriority);
1878 dev_flow->verbs.attr.port = (uint8_t)priv->dev_port;
1883 * Remove the flow from the NIC but keeps it in memory.
1886 * Pointer to the Ethernet device structure.
1887 * @param[in, out] flow
1888 * Pointer to flow structure.
1891 flow_verbs_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
1893 struct mlx5_priv *priv = dev->data->dev_private;
1894 struct mlx5_flow_handle *handle;
1895 uint32_t handle_idx;
1899 SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
1900 handle_idx, handle, next) {
1901 if (handle->drv_flow) {
1902 claim_zero(mlx5_glue->destroy_flow(handle->drv_flow));
1903 handle->drv_flow = NULL;
1905 /* hrxq is union, don't touch it only the flag is set. */
1906 if (handle->rix_hrxq &&
1907 handle->fate_action == MLX5_FLOW_FATE_QUEUE) {
1908 mlx5_hrxq_release(dev, handle->rix_hrxq);
1909 handle->rix_hrxq = 0;
1911 if (handle->vf_vlan.tag && handle->vf_vlan.created)
1912 mlx5_vlan_vmwa_release(dev, &handle->vf_vlan);
1917 * Remove the flow from the NIC and the memory.
1920 * Pointer to the Ethernet device structure.
1921 * @param[in, out] flow
1922 * Pointer to flow structure.
1925 flow_verbs_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
1927 struct mlx5_priv *priv = dev->data->dev_private;
1928 struct mlx5_flow_handle *handle;
1932 flow_verbs_remove(dev, flow);
1933 while (flow->dev_handles) {
1934 uint32_t tmp_idx = flow->dev_handles;
1936 handle = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
1940 flow->dev_handles = handle->next.next;
1941 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
1944 if (flow->counter) {
1945 flow_verbs_counter_release(dev, flow->counter);
1951 * Apply the flow to the NIC.
1954 * Pointer to the Ethernet device structure.
1955 * @param[in, out] flow
1956 * Pointer to flow structure.
1958 * Pointer to error structure.
1961 * 0 on success, a negative errno value otherwise and rte_errno is set.
1964 flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
1965 struct rte_flow_error *error)
1967 struct mlx5_priv *priv = dev->data->dev_private;
1968 struct mlx5_flow_handle *handle;
1969 struct mlx5_flow *dev_flow;
1970 struct mlx5_hrxq *hrxq;
1971 uint32_t dev_handles;
1974 struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
1977 for (idx = wks->flow_idx - 1; idx >= 0; idx--) {
1978 dev_flow = &wks->flows[idx];
1979 handle = dev_flow->handle;
1980 if (handle->fate_action == MLX5_FLOW_FATE_DROP) {
1981 MLX5_ASSERT(priv->drop_queue.hrxq);
1982 hrxq = priv->drop_queue.hrxq;
1985 struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc;
1987 MLX5_ASSERT(rss_desc->queue_num);
1988 rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN;
1989 rss_desc->hash_fields = dev_flow->hash_fields;
1990 rss_desc->tunnel = !!(handle->layers &
1991 MLX5_FLOW_LAYER_TUNNEL);
1992 rss_desc->shared_rss = 0;
1993 hrxq_idx = mlx5_hrxq_get(dev, rss_desc);
1994 hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
1999 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2000 "cannot get hash queue");
2003 handle->rix_hrxq = hrxq_idx;
2006 handle->drv_flow = mlx5_glue->create_flow
2007 (hrxq->qp, &dev_flow->verbs.attr);
2008 if (!handle->drv_flow) {
2009 rte_flow_error_set(error, errno,
2010 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2012 "hardware refuses to create flow");
2015 if (priv->vmwa_context &&
2016 handle->vf_vlan.tag && !handle->vf_vlan.created) {
2018 * The rule contains the VLAN pattern.
2019 * For VF we are going to create VLAN
2020 * interface to make hypervisor set correct
2021 * e-Switch vport context.
2023 mlx5_vlan_vmwa_acquire(dev, &handle->vf_vlan);
2028 err = rte_errno; /* Save rte_errno before cleanup. */
2029 SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
2030 dev_handles, handle, next) {
2031 /* hrxq is union, don't touch it only the flag is set. */
2032 if (handle->rix_hrxq &&
2033 handle->fate_action == MLX5_FLOW_FATE_QUEUE) {
2034 mlx5_hrxq_release(dev, handle->rix_hrxq);
2035 handle->rix_hrxq = 0;
2037 if (handle->vf_vlan.tag && handle->vf_vlan.created)
2038 mlx5_vlan_vmwa_release(dev, &handle->vf_vlan);
2040 rte_errno = err; /* Restore rte_errno. */
2047 * @see rte_flow_query()
2051 flow_verbs_query(struct rte_eth_dev *dev,
2052 struct rte_flow *flow,
2053 const struct rte_flow_action *actions,
2055 struct rte_flow_error *error)
2059 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
2060 switch (actions->type) {
2061 case RTE_FLOW_ACTION_TYPE_VOID:
2063 case RTE_FLOW_ACTION_TYPE_COUNT:
2064 ret = flow_verbs_counter_query(dev, flow, data, error);
2067 return rte_flow_error_set(error, ENOTSUP,
2068 RTE_FLOW_ERROR_TYPE_ACTION,
2070 "action not supported");
2077 flow_verbs_sync_domain(struct rte_eth_dev *dev, uint32_t domains,
2081 RTE_SET_USED(domains);
2082 RTE_SET_USED(flags);
2087 const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops = {
2088 .validate = flow_verbs_validate,
2089 .prepare = flow_verbs_prepare,
2090 .translate = flow_verbs_translate,
2091 .apply = flow_verbs_apply,
2092 .remove = flow_verbs_remove,
2093 .destroy = flow_verbs_destroy,
2094 .query = flow_verbs_query,
2095 .sync_domain = flow_verbs_sync_domain,