net/mlx4: move rdma-core calls to separate file
[dpdk.git] / drivers / net / mlx4 / mlx4_flow.c
index 5c4bf8e..8b6f8a0 100644 (file)
@@ -57,7 +57,7 @@
 #include <rte_byteorder.h>
 #include <rte_errno.h>
 #include <rte_eth_ctrl.h>
-#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
 #include <rte_ether.h>
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
@@ -65,6 +65,7 @@
 
 /* PMD headers. */
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -105,6 +106,11 @@ struct mlx4_drop {
 /**
  * Convert DPDK RSS hash fields to their Verbs equivalent.
  *
+ * This function returns the supported (default) set when @p rss_hf has
+ * special value (uint64_t)-1.
+ *
+ * @param priv
+ *   Pointer to private structure.
  * @param rss_hf
  *   Hash fields in DPDK format (see struct rte_eth_rss_conf).
  *
@@ -112,8 +118,8 @@ struct mlx4_drop {
  *   A valid Verbs RSS hash fields mask for mlx4 on success, (uint64_t)-1
  *   otherwise and rte_errno is set.
  */
-static uint64_t
-mlx4_conv_rss_hf(uint64_t rss_hf)
+uint64_t
+mlx4_conv_rss_hf(struct priv *priv, uint64_t rss_hf)
 {
        enum { IPV4, IPV6, TCP, UDP, };
        const uint64_t in[] = {
@@ -133,11 +139,9 @@ mlx4_conv_rss_hf(uint64_t rss_hf)
                [TCP] = (ETH_RSS_NONFRAG_IPV4_TCP |
                         ETH_RSS_NONFRAG_IPV6_TCP |
                         ETH_RSS_IPV6_TCP_EX),
-               /*
-                * UDP support is temporarily disabled due to an
-                * implementation issue in the kernel.
-                */
-               [UDP] = 0,
+               [UDP] = (ETH_RSS_NONFRAG_IPV4_UDP |
+                        ETH_RSS_NONFRAG_IPV6_UDP |
+                        ETH_RSS_IPV6_UDP_EX),
        };
        const uint64_t out[RTE_DIM(in)] = {
                [IPV4] = IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4,
@@ -154,8 +158,15 @@ mlx4_conv_rss_hf(uint64_t rss_hf)
                        seen |= rss_hf & in[i];
                        conv |= out[i];
                }
-       if (!(rss_hf & ~seen))
-               return conv;
+       if ((conv & priv->hw_rss_sup) == conv) {
+               if (rss_hf == (uint64_t)-1) {
+                       /* Include inner RSS by default if supported. */
+                       conv |= priv->hw_rss_sup & IBV_RX_HASH_INNER;
+                       return conv;
+               }
+               if (!(rss_hf & ~seen))
+                       return conv;
+       }
        rte_errno = ENOTSUP;
        return (uint64_t)-1;
 }
@@ -404,7 +415,7 @@ mlx4_flow_merge_udp(struct rte_flow *flow,
        struct ibv_flow_spec_tcp_udp *udp;
        const char *msg;
 
-       if (!mask ||
+       if (mask &&
            ((uint16_t)(mask->hdr.src_port + 1) > UINT16_C(1) ||
             (uint16_t)(mask->hdr.dst_port + 1) > UINT16_C(1))) {
                msg = "mlx4 does not support matching partial UDP fields";
@@ -464,7 +475,7 @@ mlx4_flow_merge_tcp(struct rte_flow *flow,
        struct ibv_flow_spec_tcp_udp *tcp;
        const char *msg;
 
-       if (!mask ||
+       if (mask &&
            ((uint16_t)(mask->hdr.src_port + 1) > UINT16_C(1) ||
             (uint16_t)(mask->hdr.dst_port + 1) > UINT16_C(1))) {
                msg = "mlx4 does not support matching partial TCP fields";
@@ -734,6 +745,11 @@ fill:
                        if (flow->rss)
                                break;
                        queue = action->conf;
+                       if (queue->index >= priv->dev->data->nb_rx_queues) {
+                               msg = "queue target index beyond number of"
+                                       " configured Rx queues";
+                               goto exit_action_not_supported;
+                       }
                        flow->rss = mlx4_rss_get
                                (priv, 0, mlx4_rss_hash_key_default, 1,
                                 &queue->index);
@@ -754,12 +770,18 @@ fill:
                                &(struct rte_eth_rss_conf){
                                        .rss_key = mlx4_rss_hash_key_default,
                                        .rss_key_len = MLX4_RSS_HASH_KEY_SIZE,
-                                       .rss_hf = (ETH_RSS_IPV4 |
-                                                  ETH_RSS_NONFRAG_IPV4_TCP |
-                                                  ETH_RSS_IPV6 |
-                                                  ETH_RSS_NONFRAG_IPV6_TCP),
+                                       .rss_hf = -1,
                                };
                        /* Sanity checks. */
+                       for (i = 0; i < rss->num; ++i)
+                               if (rss->queue[i] >=
+                                   priv->dev->data->nb_rx_queues)
+                                       break;
+                       if (i != rss->num) {
+                               msg = "queue index target beyond number of"
+                                       " configured Rx queues";
+                               goto exit_action_not_supported;
+                       }
                        if (!rte_is_power_of_2(rss->num)) {
                                msg = "for RSS, mlx4 requires the number of"
                                        " queues to be a power of two";
@@ -787,7 +809,8 @@ fill:
                                goto exit_action_not_supported;
                        }
                        flow->rss = mlx4_rss_get
-                               (priv, mlx4_conv_rss_hf(rss_conf->rss_hf),
+                               (priv,
+                                mlx4_conv_rss_hf(priv, rss_conf->rss_hf),
                                 rss_conf->rss_key, rss->num, rss->queue);
                        if (!flow->rss) {
                                msg = "either invalid parameters or not enough"
@@ -900,24 +923,25 @@ mlx4_drop_get(struct priv *priv)
                .priv = priv,
                .refcnt = 1,
        };
-       drop->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+       drop->cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
        if (!drop->cq)
                goto error;
-       drop->qp = ibv_create_qp(priv->pd,
-                                &(struct ibv_qp_init_attr){
-                                       .send_cq = drop->cq,
-                                       .recv_cq = drop->cq,
-                                       .qp_type = IBV_QPT_RAW_PACKET,
-                                });
+       drop->qp = mlx4_glue->create_qp
+               (priv->pd,
+                &(struct ibv_qp_init_attr){
+                       .send_cq = drop->cq,
+                       .recv_cq = drop->cq,
+                       .qp_type = IBV_QPT_RAW_PACKET,
+                });
        if (!drop->qp)
                goto error;
        priv->drop = drop;
        return drop;
 error:
        if (drop->qp)
-               claim_zero(ibv_destroy_qp(drop->qp));
+               claim_zero(mlx4_glue->destroy_qp(drop->qp));
        if (drop->cq)
-               claim_zero(ibv_destroy_cq(drop->cq));
+               claim_zero(mlx4_glue->destroy_cq(drop->cq));
        if (drop)
                rte_free(drop);
        rte_errno = ENOMEM;
@@ -937,8 +961,8 @@ mlx4_drop_put(struct mlx4_drop *drop)
        if (--drop->refcnt)
                return;
        drop->priv->drop = NULL;
-       claim_zero(ibv_destroy_qp(drop->qp));
-       claim_zero(ibv_destroy_cq(drop->cq));
+       claim_zero(mlx4_glue->destroy_qp(drop->qp));
+       claim_zero(mlx4_glue->destroy_cq(drop->cq));
        rte_free(drop);
 }
 
@@ -970,7 +994,7 @@ mlx4_flow_toggle(struct priv *priv,
        if (!enable) {
                if (!flow->ibv_flow)
                        return 0;
-               claim_zero(ibv_destroy_flow(flow->ibv_flow));
+               claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
                flow->ibv_flow = NULL;
                if (flow->drop)
                        mlx4_drop_put(priv->drop);
@@ -983,7 +1007,7 @@ mlx4_flow_toggle(struct priv *priv,
            !priv->isolated &&
            flow->ibv_attr->priority == MLX4_FLOW_PRIORITY_LAST) {
                if (flow->ibv_flow) {
-                       claim_zero(ibv_destroy_flow(flow->ibv_flow));
+                       claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
                        flow->ibv_flow = NULL;
                        if (flow->drop)
                                mlx4_drop_put(priv->drop);
@@ -1013,7 +1037,7 @@ mlx4_flow_toggle(struct priv *priv,
                        if (missing ^ !flow->drop)
                                return 0;
                        /* Verbs flow needs updating. */
-                       claim_zero(ibv_destroy_flow(flow->ibv_flow));
+                       claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
                        flow->ibv_flow = NULL;
                        if (flow->drop)
                                mlx4_drop_put(priv->drop);
@@ -1045,7 +1069,7 @@ mlx4_flow_toggle(struct priv *priv,
        assert(qp);
        if (flow->ibv_flow)
                return 0;
-       flow->ibv_flow = ibv_create_flow(qp, flow->ibv_attr);
+       flow->ibv_flow = mlx4_glue->create_flow(qp, flow->ibv_attr);
        if (flow->ibv_flow)
                return 0;
        if (flow->drop)
@@ -1201,16 +1225,19 @@ mlx4_flow_internal_next_vlan(struct priv *priv, uint16_t vlan)
  *
  * Various flow rules are created depending on the mode the device is in:
  *
- * 1. Promiscuous: port MAC + catch-all (VLAN filtering is ignored).
- * 2. All multicast: port MAC/VLAN + catch-all multicast.
- * 3. Otherwise: port MAC/VLAN + broadcast MAC/VLAN.
+ * 1. Promiscuous:
+ *       port MAC + broadcast + catch-all (VLAN filtering is ignored).
+ * 2. All multicast:
+ *       port MAC/VLAN + broadcast + catch-all multicast.
+ * 3. Otherwise:
+ *       port MAC/VLAN + broadcast MAC/VLAN.
  *
  * About MAC flow rules:
  *
  * - MAC flow rules are generated from @p dev->data->mac_addrs
  *   (@p priv->mac array).
  * - An additional flow rule for Ethernet broadcasts is also generated.
- * - All these are per-VLAN if @p dev->data->dev_conf.rxmode.hw_vlan_filter
+ * - All these are per-VLAN if @p DEV_RX_OFFLOAD_VLAN_FILTER
  *   is enabled and VLAN filters are configured.
  *
  * @param priv
@@ -1278,18 +1305,19 @@ mlx4_flow_internal(struct priv *priv, struct rte_flow_error *error)
        };
        struct ether_addr *rule_mac = &eth_spec.dst;
        rte_be16_t *rule_vlan =
-               priv->dev->data->dev_conf.rxmode.hw_vlan_filter &&
+               (priv->dev->data->dev_conf.rxmode.offloads &
+                DEV_RX_OFFLOAD_VLAN_FILTER) &&
                !priv->dev->data->promiscuous ?
                &vlan_spec.tci :
                NULL;
-       int broadcast =
-               !priv->dev->data->promiscuous &&
-               !priv->dev->data->all_multicast;
        uint16_t vlan = 0;
        struct rte_flow *flow;
        unsigned int i;
        int err = 0;
 
+       /* Nothing to be done if there are no Rx queues. */
+       if (!queues)
+               goto error;
        /* Prepare default RSS configuration. */
        *rss_conf = (struct rte_flow_action_rss){
                .rss_conf = NULL, /* Rely on default fallback settings. */
@@ -1315,7 +1343,7 @@ next_vlan:
                        rule_vlan = NULL;
                }
        }
-       for (i = 0; i != RTE_DIM(priv->mac) + broadcast; ++i) {
+       for (i = 0; i != RTE_DIM(priv->mac) + 1; ++i) {
                const struct ether_addr *mac;
 
                /* Broadcasts are handled by an extra iteration. */
@@ -1339,6 +1367,7 @@ next_vlan:
                        assert(flow->ibv_attr->type == IBV_FLOW_ATTR_NORMAL);
                        assert(flow->ibv_attr->num_of_specs == 1);
                        assert(eth->type == IBV_FLOW_SPEC_ETH);
+                       assert(flow->rss);
                        if (rule_vlan &&
                            (eth->val.vlan_tag != *rule_vlan ||
                             eth->mask.vlan_tag != RTE_BE16(0x0fff)))
@@ -1351,8 +1380,13 @@ next_vlan:
                                    eth->val.src_mac[j] != UINT8_C(0x00) ||
                                    eth->mask.src_mac[j] != UINT8_C(0x00))
                                        break;
-                       if (j == sizeof(mac->addr_bytes))
-                               break;
+                       if (j != sizeof(mac->addr_bytes))
+                               continue;
+                       if (flow->rss->queues != queues ||
+                           memcmp(flow->rss->queue_id, rss_conf->queue,
+                                  queues * sizeof(flow->rss->queue_id[0])))
+                               continue;
+                       break;
                }
                if (!flow || !flow->internal) {
                        /* Not found, create a new flow rule. */
@@ -1373,7 +1407,7 @@ next_vlan:
                        goto next_vlan;
        }
        /* Take care of promiscuous and all multicast flow rules. */
-       if (!broadcast) {
+       if (priv->dev->data->promiscuous || priv->dev->data->all_multicast) {
                for (flow = LIST_FIRST(&priv->flows);
                     flow && flow->internal;
                     flow = LIST_NEXT(flow, next)) {
@@ -1386,6 +1420,13 @@ next_vlan:
                                        break;
                        }
                }
+               if (flow && flow->internal) {
+                       assert(flow->rss);
+                       if (flow->rss->queues != queues ||
+                           memcmp(flow->rss->queue_id, rss_conf->queue,
+                                  queues * sizeof(flow->rss->queue_id[0])))
+                               flow = NULL;
+               }
                if (!flow || !flow->internal) {
                        /* Not found, create a new flow rule. */
                        if (priv->dev->data->promiscuous) {
@@ -1460,9 +1501,7 @@ mlx4_flow_sync(struct priv *priv, struct rte_flow_error *error)
                        return ret;
        }
        /* Toggle the remaining flow rules . */
-       for (flow = LIST_FIRST(&priv->flows);
-            flow;
-            flow = LIST_NEXT(flow, next)) {
+       LIST_FOREACH(flow, &priv->flows, next) {
                ret = mlx4_flow_toggle(priv, flow, priv->started, error);
                if (ret)
                        return ret;