4 * Copyright 2017 6WIND S.A.
5 * Copyright 2017 Mellanox
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of 6WIND S.A. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * Flow API operations for mlx4 driver.
39 #include <arpa/inet.h>
46 #include <sys/queue.h>
48 /* Verbs headers do not support -pedantic. */
50 #pragma GCC diagnostic ignored "-Wpedantic"
52 #include <infiniband/verbs.h>
54 #pragma GCC diagnostic error "-Wpedantic"
57 #include <rte_byteorder.h>
58 #include <rte_errno.h>
59 #include <rte_eth_ctrl.h>
60 #include <rte_ethdev.h>
62 #include <rte_flow_driver.h>
63 #include <rte_malloc.h>
67 #include "mlx4_flow.h"
68 #include "mlx4_rxtx.h"
69 #include "mlx4_utils.h"
71 /** Static initializer for a list of subsequent item types. */
72 #define NEXT_ITEM(...) \
73 (const enum rte_flow_item_type []){ \
74 __VA_ARGS__, RTE_FLOW_ITEM_TYPE_END, \
77 /** Processor structure associated with a flow item. */
78 struct mlx4_flow_proc_item {
79 /** Bit-mask for fields supported by this PMD. */
80 const void *mask_support;
81 /** Bit-mask to use when @p item->mask is not provided. */
82 const void *mask_default;
83 /** Size in bytes for @p mask_support and @p mask_default. */
84 const unsigned int mask_sz;
85 /** Merge a pattern item into a flow rule handle. */
86 int (*merge)(struct rte_flow *flow,
87 const struct rte_flow_item *item,
88 const struct mlx4_flow_proc_item *proc,
89 struct rte_flow_error *error);
90 /** Size in bytes of the destination structure. */
91 const unsigned int dst_sz;
92 /** List of possible subsequent items. */
93 const enum rte_flow_item_type *const next_item;
96 /** Shared resources for drop flow rules. */
98 struct ibv_qp *qp; /**< QP target. */
99 struct ibv_cq *cq; /**< CQ associated with above QP. */
100 struct priv *priv; /**< Back pointer to private data. */
101 uint32_t refcnt; /**< Reference count. */
105 * Merge Ethernet pattern item into flow rule handle.
107 * Additional mlx4-specific constraints on supported fields:
109 * - No support for partial masks.
110 * - Not providing @p item->spec or providing an empty @p mask->dst is
111 * *only* supported if the rule doesn't specify additional matching
112 * criteria (i.e. rule is promiscuous-like).
114 * @param[in, out] flow
115 * Flow rule handle to update.
117 * Pattern item to merge.
119 * Associated item-processing object.
121 * Perform verbose error reporting if not NULL.
124 * 0 on success, a negative errno value otherwise and rte_errno is set.
127 mlx4_flow_merge_eth(struct rte_flow *flow,
128 const struct rte_flow_item *item,
129 const struct mlx4_flow_proc_item *proc,
130 struct rte_flow_error *error)
132 const struct rte_flow_item_eth *spec = item->spec;
133 const struct rte_flow_item_eth *mask =
134 spec ? (item->mask ? item->mask : proc->mask_default) : NULL;
135 struct ibv_flow_spec_eth *eth;
142 uint32_t sum_dst = 0;
143 uint32_t sum_src = 0;
145 for (i = 0; i != sizeof(mask->dst.addr_bytes); ++i) {
146 sum_dst += mask->dst.addr_bytes[i];
147 sum_src += mask->src.addr_bytes[i];
150 msg = "mlx4 does not support source MAC matching";
152 } else if (!sum_dst) {
154 } else if (sum_dst != (UINT8_C(0xff) * ETHER_ADDR_LEN)) {
155 msg = "mlx4 does not support matching partial"
163 flow->ibv_attr->type = IBV_FLOW_ATTR_ALL_DEFAULT;
166 ++flow->ibv_attr->num_of_specs;
167 eth = (void *)((uintptr_t)flow->ibv_attr + flow->ibv_attr_size);
168 *eth = (struct ibv_flow_spec_eth) {
169 .type = IBV_FLOW_SPEC_ETH,
170 .size = sizeof(*eth),
172 memcpy(eth->val.dst_mac, spec->dst.addr_bytes, ETHER_ADDR_LEN);
173 memcpy(eth->mask.dst_mac, mask->dst.addr_bytes, ETHER_ADDR_LEN);
174 /* Remove unwanted bits from values. */
175 for (i = 0; i < ETHER_ADDR_LEN; ++i) {
176 eth->val.dst_mac[i] &= eth->mask.dst_mac[i];
180 return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
185 * Merge VLAN pattern item into flow rule handle.
187 * Additional mlx4-specific constraints on supported fields:
189 * - Matching *all* VLAN traffic by omitting @p item->spec or providing an
190 * empty @p item->mask would also include non-VLAN traffic. Doing so is
191 * therefore unsupported.
192 * - No support for partial masks.
194 * @param[in, out] flow
195 * Flow rule handle to update.
197 * Pattern item to merge.
199 * Associated item-processing object.
201 * Perform verbose error reporting if not NULL.
204 * 0 on success, a negative errno value otherwise and rte_errno is set.
207 mlx4_flow_merge_vlan(struct rte_flow *flow,
208 const struct rte_flow_item *item,
209 const struct mlx4_flow_proc_item *proc,
210 struct rte_flow_error *error)
212 const struct rte_flow_item_vlan *spec = item->spec;
213 const struct rte_flow_item_vlan *mask =
214 spec ? (item->mask ? item->mask : proc->mask_default) : NULL;
215 struct ibv_flow_spec_eth *eth;
218 if (!mask || !mask->tci) {
219 msg = "mlx4 cannot match all VLAN traffic while excluding"
220 " non-VLAN traffic, TCI VID must be specified";
223 if (mask->tci != RTE_BE16(0x0fff)) {
224 msg = "mlx4 does not support partial TCI VID matching";
229 eth = (void *)((uintptr_t)flow->ibv_attr + flow->ibv_attr_size -
231 eth->val.vlan_tag = spec->tci;
232 eth->mask.vlan_tag = mask->tci;
233 eth->val.vlan_tag &= eth->mask.vlan_tag;
236 return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
241 * Merge IPv4 pattern item into flow rule handle.
243 * Additional mlx4-specific constraints on supported fields:
245 * - No support for partial masks.
247 * @param[in, out] flow
248 * Flow rule handle to update.
250 * Pattern item to merge.
252 * Associated item-processing object.
254 * Perform verbose error reporting if not NULL.
257 * 0 on success, a negative errno value otherwise and rte_errno is set.
260 mlx4_flow_merge_ipv4(struct rte_flow *flow,
261 const struct rte_flow_item *item,
262 const struct mlx4_flow_proc_item *proc,
263 struct rte_flow_error *error)
265 const struct rte_flow_item_ipv4 *spec = item->spec;
266 const struct rte_flow_item_ipv4 *mask =
267 spec ? (item->mask ? item->mask : proc->mask_default) : NULL;
268 struct ibv_flow_spec_ipv4 *ipv4;
272 ((uint32_t)(mask->hdr.src_addr + 1) > UINT32_C(1) ||
273 (uint32_t)(mask->hdr.dst_addr + 1) > UINT32_C(1))) {
274 msg = "mlx4 does not support matching partial IPv4 fields";
279 ++flow->ibv_attr->num_of_specs;
280 ipv4 = (void *)((uintptr_t)flow->ibv_attr + flow->ibv_attr_size);
281 *ipv4 = (struct ibv_flow_spec_ipv4) {
282 .type = IBV_FLOW_SPEC_IPV4,
283 .size = sizeof(*ipv4),
287 ipv4->val = (struct ibv_flow_ipv4_filter) {
288 .src_ip = spec->hdr.src_addr,
289 .dst_ip = spec->hdr.dst_addr,
291 ipv4->mask = (struct ibv_flow_ipv4_filter) {
292 .src_ip = mask->hdr.src_addr,
293 .dst_ip = mask->hdr.dst_addr,
295 /* Remove unwanted bits from values. */
296 ipv4->val.src_ip &= ipv4->mask.src_ip;
297 ipv4->val.dst_ip &= ipv4->mask.dst_ip;
300 return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
305 * Merge UDP pattern item into flow rule handle.
307 * Additional mlx4-specific constraints on supported fields:
309 * - No support for partial masks.
311 * @param[in, out] flow
312 * Flow rule handle to update.
314 * Pattern item to merge.
316 * Associated item-processing object.
318 * Perform verbose error reporting if not NULL.
321 * 0 on success, a negative errno value otherwise and rte_errno is set.
324 mlx4_flow_merge_udp(struct rte_flow *flow,
325 const struct rte_flow_item *item,
326 const struct mlx4_flow_proc_item *proc,
327 struct rte_flow_error *error)
329 const struct rte_flow_item_udp *spec = item->spec;
330 const struct rte_flow_item_udp *mask =
331 spec ? (item->mask ? item->mask : proc->mask_default) : NULL;
332 struct ibv_flow_spec_tcp_udp *udp;
336 ((uint16_t)(mask->hdr.src_port + 1) > UINT16_C(1) ||
337 (uint16_t)(mask->hdr.dst_port + 1) > UINT16_C(1))) {
338 msg = "mlx4 does not support matching partial UDP fields";
343 ++flow->ibv_attr->num_of_specs;
344 udp = (void *)((uintptr_t)flow->ibv_attr + flow->ibv_attr_size);
345 *udp = (struct ibv_flow_spec_tcp_udp) {
346 .type = IBV_FLOW_SPEC_UDP,
347 .size = sizeof(*udp),
351 udp->val.dst_port = spec->hdr.dst_port;
352 udp->val.src_port = spec->hdr.src_port;
353 udp->mask.dst_port = mask->hdr.dst_port;
354 udp->mask.src_port = mask->hdr.src_port;
355 /* Remove unwanted bits from values. */
356 udp->val.src_port &= udp->mask.src_port;
357 udp->val.dst_port &= udp->mask.dst_port;
360 return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
365 * Merge TCP pattern item into flow rule handle.
367 * Additional mlx4-specific constraints on supported fields:
369 * - No support for partial masks.
371 * @param[in, out] flow
372 * Flow rule handle to update.
374 * Pattern item to merge.
376 * Associated item-processing object.
378 * Perform verbose error reporting if not NULL.
381 * 0 on success, a negative errno value otherwise and rte_errno is set.
384 mlx4_flow_merge_tcp(struct rte_flow *flow,
385 const struct rte_flow_item *item,
386 const struct mlx4_flow_proc_item *proc,
387 struct rte_flow_error *error)
389 const struct rte_flow_item_tcp *spec = item->spec;
390 const struct rte_flow_item_tcp *mask =
391 spec ? (item->mask ? item->mask : proc->mask_default) : NULL;
392 struct ibv_flow_spec_tcp_udp *tcp;
396 ((uint16_t)(mask->hdr.src_port + 1) > UINT16_C(1) ||
397 (uint16_t)(mask->hdr.dst_port + 1) > UINT16_C(1))) {
398 msg = "mlx4 does not support matching partial TCP fields";
403 ++flow->ibv_attr->num_of_specs;
404 tcp = (void *)((uintptr_t)flow->ibv_attr + flow->ibv_attr_size);
405 *tcp = (struct ibv_flow_spec_tcp_udp) {
406 .type = IBV_FLOW_SPEC_TCP,
407 .size = sizeof(*tcp),
411 tcp->val.dst_port = spec->hdr.dst_port;
412 tcp->val.src_port = spec->hdr.src_port;
413 tcp->mask.dst_port = mask->hdr.dst_port;
414 tcp->mask.src_port = mask->hdr.src_port;
415 /* Remove unwanted bits from values. */
416 tcp->val.src_port &= tcp->mask.src_port;
417 tcp->val.dst_port &= tcp->mask.dst_port;
420 return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
425 * Perform basic sanity checks on a pattern item.
428 * Item specification.
430 * Associated item-processing object.
432 * Perform verbose error reporting if not NULL.
435 * 0 on success, a negative errno value otherwise and rte_errno is set.
438 mlx4_flow_item_check(const struct rte_flow_item *item,
439 const struct mlx4_flow_proc_item *proc,
440 struct rte_flow_error *error)
445 /* item->last and item->mask cannot exist without item->spec. */
446 if (!item->spec && (item->mask || item->last))
447 return rte_flow_error_set
448 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
449 "\"mask\" or \"last\" field provided without a"
450 " corresponding \"spec\"");
451 /* No spec, no mask, no problem. */
455 (const uint8_t *)item->mask :
456 (const uint8_t *)proc->mask_default;
459 * Single-pass check to make sure that:
460 * - Mask is supported, no bits are set outside proc->mask_support.
461 * - Both item->spec and item->last are included in mask.
463 for (i = 0; i != proc->mask_sz; ++i) {
466 if ((mask[i] | ((const uint8_t *)proc->mask_support)[i]) !=
467 ((const uint8_t *)proc->mask_support)[i])
468 return rte_flow_error_set
469 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
470 item, "unsupported field found in \"mask\"");
472 (((const uint8_t *)item->spec)[i] & mask[i]) !=
473 (((const uint8_t *)item->last)[i] & mask[i]))
474 return rte_flow_error_set
475 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
477 "range between \"spec\" and \"last\""
478 " is larger than \"mask\"");
483 /** Graph of supported items and associated actions. */
484 static const struct mlx4_flow_proc_item mlx4_flow_proc_item_list[] = {
485 [RTE_FLOW_ITEM_TYPE_END] = {
486 .next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_ETH),
488 [RTE_FLOW_ITEM_TYPE_ETH] = {
489 .next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_VLAN,
490 RTE_FLOW_ITEM_TYPE_IPV4),
491 .mask_support = &(const struct rte_flow_item_eth){
492 /* Only destination MAC can be matched. */
493 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
495 .mask_default = &rte_flow_item_eth_mask,
496 .mask_sz = sizeof(struct rte_flow_item_eth),
497 .merge = mlx4_flow_merge_eth,
498 .dst_sz = sizeof(struct ibv_flow_spec_eth),
500 [RTE_FLOW_ITEM_TYPE_VLAN] = {
501 .next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_IPV4),
502 .mask_support = &(const struct rte_flow_item_vlan){
503 /* Only TCI VID matching is supported. */
504 .tci = RTE_BE16(0x0fff),
506 .mask_default = &rte_flow_item_vlan_mask,
507 .mask_sz = sizeof(struct rte_flow_item_vlan),
508 .merge = mlx4_flow_merge_vlan,
511 [RTE_FLOW_ITEM_TYPE_IPV4] = {
512 .next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_UDP,
513 RTE_FLOW_ITEM_TYPE_TCP),
514 .mask_support = &(const struct rte_flow_item_ipv4){
516 .src_addr = RTE_BE32(0xffffffff),
517 .dst_addr = RTE_BE32(0xffffffff),
520 .mask_default = &rte_flow_item_ipv4_mask,
521 .mask_sz = sizeof(struct rte_flow_item_ipv4),
522 .merge = mlx4_flow_merge_ipv4,
523 .dst_sz = sizeof(struct ibv_flow_spec_ipv4),
525 [RTE_FLOW_ITEM_TYPE_UDP] = {
526 .mask_support = &(const struct rte_flow_item_udp){
528 .src_port = RTE_BE16(0xffff),
529 .dst_port = RTE_BE16(0xffff),
532 .mask_default = &rte_flow_item_udp_mask,
533 .mask_sz = sizeof(struct rte_flow_item_udp),
534 .merge = mlx4_flow_merge_udp,
535 .dst_sz = sizeof(struct ibv_flow_spec_tcp_udp),
537 [RTE_FLOW_ITEM_TYPE_TCP] = {
538 .mask_support = &(const struct rte_flow_item_tcp){
540 .src_port = RTE_BE16(0xffff),
541 .dst_port = RTE_BE16(0xffff),
544 .mask_default = &rte_flow_item_tcp_mask,
545 .mask_sz = sizeof(struct rte_flow_item_tcp),
546 .merge = mlx4_flow_merge_tcp,
547 .dst_sz = sizeof(struct ibv_flow_spec_tcp_udp),
552 * Make sure a flow rule is supported and initialize associated structure.
555 * Pointer to private structure.
557 * Flow rule attributes.
559 * Pattern specification (list terminated by the END pattern item).
561 * Associated actions (list terminated by the END action).
563 * Perform verbose error reporting if not NULL.
564 * @param[in, out] addr
565 * Buffer where the resulting flow rule handle pointer must be stored.
566 * If NULL, stop processing after validation stage.
569 * 0 on success, a negative errno value otherwise and rte_errno is set.
572 mlx4_flow_prepare(struct priv *priv,
573 const struct rte_flow_attr *attr,
574 const struct rte_flow_item pattern[],
575 const struct rte_flow_action actions[],
576 struct rte_flow_error *error,
577 struct rte_flow **addr)
579 const struct rte_flow_item *item;
580 const struct rte_flow_action *action;
581 const struct mlx4_flow_proc_item *proc;
582 struct rte_flow temp = { .ibv_attr_size = sizeof(*temp.ibv_attr) };
583 struct rte_flow *flow = &temp;
584 const char *msg = NULL;
587 return rte_flow_error_set
588 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
589 NULL, "groups are not supported");
590 if (attr->priority > MLX4_FLOW_PRIORITY_LAST)
591 return rte_flow_error_set
592 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
593 NULL, "maximum priority level is "
594 MLX4_STR_EXPAND(MLX4_FLOW_PRIORITY_LAST));
596 return rte_flow_error_set
597 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
598 NULL, "egress is not supported");
600 return rte_flow_error_set
601 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
602 NULL, "only ingress is supported");
604 proc = mlx4_flow_proc_item_list;
605 /* Go over pattern. */
606 for (item = pattern; item->type; ++item) {
607 const struct mlx4_flow_proc_item *next = NULL;
611 if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
613 if (item->type == MLX4_FLOW_ITEM_TYPE_INTERNAL) {
618 msg = "mlx4 does not support additional matching"
619 " criteria combined with indiscriminate"
620 " matching on Ethernet headers";
621 goto exit_item_not_supported;
623 for (i = 0; proc->next_item && proc->next_item[i]; ++i) {
624 if (proc->next_item[i] == item->type) {
625 next = &mlx4_flow_proc_item_list[item->type];
630 goto exit_item_not_supported;
633 * Perform basic sanity checks only once, while handle is
637 err = mlx4_flow_item_check(item, proc, error);
642 err = proc->merge(flow, item, proc, error);
646 flow->ibv_attr_size += proc->dst_sz;
648 /* Go over actions list. */
649 for (action = actions; action->type; ++action) {
650 switch (action->type) {
651 const struct rte_flow_action_queue *queue;
653 case RTE_FLOW_ACTION_TYPE_VOID:
655 case RTE_FLOW_ACTION_TYPE_DROP:
658 case RTE_FLOW_ACTION_TYPE_QUEUE:
659 queue = action->conf;
660 if (queue->index >= priv->dev->data->nb_rx_queues)
661 goto exit_action_not_supported;
663 flow->queue_id = queue->index;
666 goto exit_action_not_supported;
669 if (!flow->queue && !flow->drop)
670 return rte_flow_error_set
671 (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
672 NULL, "no valid action");
673 /* Validation ends here. */
677 /* Allocate proper handle based on collected data. */
678 const struct mlx4_malloc_vec vec[] = {
680 .align = alignof(struct rte_flow),
681 .size = sizeof(*flow),
682 .addr = (void **)&flow,
685 .align = alignof(struct ibv_flow_attr),
686 .size = temp.ibv_attr_size,
687 .addr = (void **)&temp.ibv_attr,
691 if (!mlx4_zmallocv(__func__, vec, RTE_DIM(vec)))
692 return rte_flow_error_set
694 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
695 "flow rule handle allocation failure");
696 /* Most fields will be updated by second pass. */
697 *flow = (struct rte_flow){
698 .ibv_attr = temp.ibv_attr,
699 .ibv_attr_size = sizeof(*flow->ibv_attr),
701 *flow->ibv_attr = (struct ibv_flow_attr){
702 .type = IBV_FLOW_ATTR_NORMAL,
703 .size = sizeof(*flow->ibv_attr),
704 .priority = attr->priority,
711 exit_item_not_supported:
712 return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
713 item, msg ? msg : "item not supported");
714 exit_action_not_supported:
715 return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
716 action, "action not supported");
720 * Validate a flow supported by the NIC.
722 * @see rte_flow_validate()
726 mlx4_flow_validate(struct rte_eth_dev *dev,
727 const struct rte_flow_attr *attr,
728 const struct rte_flow_item pattern[],
729 const struct rte_flow_action actions[],
730 struct rte_flow_error *error)
732 struct priv *priv = dev->data->dev_private;
734 return mlx4_flow_prepare(priv, attr, pattern, actions, error, NULL);
738 * Get a drop flow rule resources instance.
741 * Pointer to private structure.
744 * Pointer to drop flow resources on success, NULL otherwise and rte_errno
747 static struct mlx4_drop *
748 mlx4_drop_get(struct priv *priv)
750 struct mlx4_drop *drop = priv->drop;
753 assert(drop->refcnt);
754 assert(drop->priv == priv);
758 drop = rte_malloc(__func__, sizeof(*drop), 0);
761 *drop = (struct mlx4_drop){
765 drop->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
768 drop->qp = ibv_create_qp(priv->pd,
769 &(struct ibv_qp_init_attr){
772 .qp_type = IBV_QPT_RAW_PACKET,
780 claim_zero(ibv_destroy_qp(drop->qp));
782 claim_zero(ibv_destroy_cq(drop->cq));
790 * Give back a drop flow rule resources instance.
793 * Pointer to drop flow rule resources.
796 mlx4_drop_put(struct mlx4_drop *drop)
798 assert(drop->refcnt);
801 drop->priv->drop = NULL;
802 claim_zero(ibv_destroy_qp(drop->qp));
803 claim_zero(ibv_destroy_cq(drop->cq));
808 * Toggle a configured flow rule.
811 * Pointer to private structure.
813 * Flow rule handle to toggle.
815 * Whether associated Verbs flow must be created or removed.
817 * Perform verbose error reporting if not NULL.
820 * 0 on success, a negative errno value otherwise and rte_errno is set.
823 mlx4_flow_toggle(struct priv *priv,
824 struct rte_flow *flow,
826 struct rte_flow_error *error)
828 struct ibv_qp *qp = NULL;
835 claim_zero(ibv_destroy_flow(flow->ibv_flow));
836 flow->ibv_flow = NULL;
838 mlx4_drop_put(priv->drop);
841 assert(flow->ibv_attr);
842 if (!flow->internal &&
844 flow->ibv_attr->priority == MLX4_FLOW_PRIORITY_LAST) {
845 if (flow->ibv_flow) {
846 claim_zero(ibv_destroy_flow(flow->ibv_flow));
847 flow->ibv_flow = NULL;
849 mlx4_drop_put(priv->drop);
852 msg = ("priority level "
853 MLX4_STR_EXPAND(MLX4_FLOW_PRIORITY_LAST)
854 " is reserved when not in isolated mode");
858 struct rxq *rxq = NULL;
860 if (flow->queue_id < priv->dev->data->nb_rx_queues)
861 rxq = priv->dev->data->rx_queues[flow->queue_id];
862 if (flow->ibv_flow) {
863 if (!rxq ^ !flow->drop)
865 /* Verbs flow needs updating. */
866 claim_zero(ibv_destroy_flow(flow->ibv_flow));
867 flow->ibv_flow = NULL;
869 mlx4_drop_put(priv->drop);
873 /* A missing target queue drops traffic implicitly. */
880 msg = "resources for drop flow rule cannot be created";
888 flow->ibv_flow = ibv_create_flow(qp, flow->ibv_attr);
892 mlx4_drop_put(priv->drop);
894 msg = "flow rule rejected by device";
896 return rte_flow_error_set
897 (error, err, RTE_FLOW_ERROR_TYPE_HANDLE, flow, msg);
903 * @see rte_flow_create()
906 static struct rte_flow *
907 mlx4_flow_create(struct rte_eth_dev *dev,
908 const struct rte_flow_attr *attr,
909 const struct rte_flow_item pattern[],
910 const struct rte_flow_action actions[],
911 struct rte_flow_error *error)
913 struct priv *priv = dev->data->dev_private;
914 struct rte_flow *flow;
917 err = mlx4_flow_prepare(priv, attr, pattern, actions, error, &flow);
920 err = mlx4_flow_toggle(priv, flow, priv->started, error);
922 struct rte_flow *curr = LIST_FIRST(&priv->flows);
924 /* New rules are inserted after internal ones. */
925 if (!curr || !curr->internal) {
926 LIST_INSERT_HEAD(&priv->flows, flow, next);
928 while (LIST_NEXT(curr, next) &&
929 LIST_NEXT(curr, next)->internal)
930 curr = LIST_NEXT(curr, next);
931 LIST_INSERT_AFTER(curr, flow, next);
935 rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
942 * Configure isolated mode.
944 * @see rte_flow_isolate()
948 mlx4_flow_isolate(struct rte_eth_dev *dev,
950 struct rte_flow_error *error)
952 struct priv *priv = dev->data->dev_private;
954 if (!!enable == !!priv->isolated)
956 priv->isolated = !!enable;
957 if (mlx4_flow_sync(priv, error)) {
958 priv->isolated = !enable;
965 * Destroy a flow rule.
967 * @see rte_flow_destroy()
971 mlx4_flow_destroy(struct rte_eth_dev *dev,
972 struct rte_flow *flow,
973 struct rte_flow_error *error)
975 struct priv *priv = dev->data->dev_private;
976 int err = mlx4_flow_toggle(priv, flow, 0, error);
980 LIST_REMOVE(flow, next);
986 * Destroy user-configured flow rules.
988 * This function skips internal flows rules.
990 * @see rte_flow_flush()
994 mlx4_flow_flush(struct rte_eth_dev *dev,
995 struct rte_flow_error *error)
997 struct priv *priv = dev->data->dev_private;
998 struct rte_flow *flow = LIST_FIRST(&priv->flows);
1001 struct rte_flow *next = LIST_NEXT(flow, next);
1003 if (!flow->internal)
1004 mlx4_flow_destroy(dev, flow, error);
1011 * Generate internal flow rules.
1014 * Pointer to private structure.
1016 * Perform verbose error reporting if not NULL.
1019 * 0 on success, a negative errno value otherwise and rte_errno is set.
1022 mlx4_flow_internal(struct priv *priv, struct rte_flow_error *error)
1024 struct rte_flow_attr attr = {
1025 .priority = MLX4_FLOW_PRIORITY_LAST,
1028 struct rte_flow_item pattern[] = {
1030 .type = MLX4_FLOW_ITEM_TYPE_INTERNAL,
1033 .type = RTE_FLOW_ITEM_TYPE_ETH,
1034 .spec = &(struct rte_flow_item_eth){
1037 .mask = &(struct rte_flow_item_eth){
1038 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
1042 .type = RTE_FLOW_ITEM_TYPE_END,
1045 struct rte_flow_action actions[] = {
1047 .type = RTE_FLOW_ACTION_TYPE_QUEUE,
1048 .conf = &(struct rte_flow_action_queue){
1053 .type = RTE_FLOW_ACTION_TYPE_END,
1057 if (!mlx4_flow_create(priv->dev, &attr, pattern, actions, error))
1063 * Synchronize flow rules.
1065 * This function synchronizes flow rules with the state of the device by
1066 * taking into account isolated mode and whether target queues are
1070 * Pointer to private structure.
1072 * Perform verbose error reporting if not NULL.
1075 * 0 on success, a negative errno value otherwise and rte_errno is set.
1078 mlx4_flow_sync(struct priv *priv, struct rte_flow_error *error)
1080 struct rte_flow *flow;
1083 /* Internal flow rules are guaranteed to come first in the list. */
1084 if (priv->isolated) {
1086 * Get rid of them in isolated mode, stop at the first
1087 * non-internal rule found.
1089 for (flow = LIST_FIRST(&priv->flows);
1090 flow && flow->internal;
1091 flow = LIST_FIRST(&priv->flows))
1092 claim_zero(mlx4_flow_destroy(priv->dev, flow, error));
1093 } else if (!LIST_FIRST(&priv->flows) ||
1094 !LIST_FIRST(&priv->flows)->internal) {
1096 * If the first rule is not internal outside isolated mode,
1097 * they must be added back.
1099 ret = mlx4_flow_internal(priv, error);
1103 /* Toggle the remaining flow rules . */
1104 for (flow = LIST_FIRST(&priv->flows);
1106 flow = LIST_NEXT(flow, next)) {
1107 ret = mlx4_flow_toggle(priv, flow, priv->started, error);
1112 assert(!priv->drop);
1117 * Clean up all flow rules.
1119 * Unlike mlx4_flow_flush(), this function takes care of all remaining flow
1120 * rules regardless of whether they are internal or user-configured.
1123 * Pointer to private structure.
1126 mlx4_flow_clean(struct priv *priv)
1128 struct rte_flow *flow;
1130 while ((flow = LIST_FIRST(&priv->flows)))
1131 mlx4_flow_destroy(priv->dev, flow, NULL);
1134 static const struct rte_flow_ops mlx4_flow_ops = {
1135 .validate = mlx4_flow_validate,
1136 .create = mlx4_flow_create,
1137 .destroy = mlx4_flow_destroy,
1138 .flush = mlx4_flow_flush,
1139 .isolate = mlx4_flow_isolate,
1143 * Manage filter operations.
1146 * Pointer to Ethernet device structure.
1147 * @param filter_type
1150 * Operation to perform.
1152 * Pointer to operation-specific structure.
1155 * 0 on success, negative errno value otherwise and rte_errno is set.
1158 mlx4_filter_ctrl(struct rte_eth_dev *dev,
1159 enum rte_filter_type filter_type,
1160 enum rte_filter_op filter_op,
1163 switch (filter_type) {
1164 case RTE_ETH_FILTER_GENERIC:
1165 if (filter_op != RTE_ETH_FILTER_GET)
1167 *(const void **)arg = &mlx4_flow_ops;
1170 ERROR("%p: filter type (%d) not supported",
1171 (void *)dev, filter_type);
1174 rte_errno = ENOTSUP;