examples/l2fwd-crypto: fix AEAD key setting
[dpdk.git] / drivers / net / mlx5 / mlx5_flow.c
index b34be55..86be929 100644 (file)
 #include "mlx5_prm.h"
 
 /* Number of Work Queue necessary for the DROP queue. */
+#ifndef HAVE_VERBS_IBV_EXP_FLOW_SPEC_ACTION_DROP
 #define MLX5_DROP_WQ_N 4
+#else
+#define MLX5_DROP_WQ_N 1
+#endif
 
 static int
 mlx5_flow_create_eth(const struct rte_flow_item *item,
@@ -91,18 +95,18 @@ mlx5_flow_create_vxlan(const struct rte_flow_item *item,
                       void *data);
 
 struct rte_flow {
-       LIST_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */
+       TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */
        struct ibv_exp_flow_attr *ibv_attr; /**< Pointer to Verbs attributes. */
        struct ibv_exp_rwq_ind_table *ind_table; /**< Indirection table. */
        struct ibv_qp *qp; /**< Verbs queue pair. */
        struct ibv_exp_flow *ibv_flow; /**< Verbs flow. */
        struct ibv_exp_wq *wq; /**< Verbs work queue. */
        struct ibv_cq *cq; /**< Verbs completion queue. */
-       struct rxq *(*rxqs)[]; /**< Pointer to the queues array. */
        uint16_t rxqs_n; /**< Number of queues in this flow, 0 if drop queue. */
        uint32_t mark:1; /**< Set if the flow is marked. */
        uint32_t drop:1; /**< Drop queue. */
        uint64_t hash_fields; /**< Fields that participate in the hash. */
+       struct rxq *rxqs[]; /**< Pointer to the queues array. */
 };
 
 /** Static initializer for items. */
@@ -488,22 +492,31 @@ priv_flow_validate(struct priv *priv,
                                        break;
                                }
                        }
-                       if (action->queues_n && !found) {
+                       if (action->queues_n > 1 && !found) {
                                rte_flow_error_set(error, ENOTSUP,
                                           RTE_FLOW_ERROR_TYPE_ACTION,
                                           actions,
                                           "queue action not in RSS queues");
                                return -rte_errno;
                        }
-                       action->queue = 1;
-                       action->queues_n = 1;
-                       action->queues[0] = queue->index;
+                       if (!found) {
+                               action->queue = 1;
+                               action->queues_n = 1;
+                               action->queues[0] = queue->index;
+                       }
                } else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
                        const struct rte_flow_action_rss *rss =
                                (const struct rte_flow_action_rss *)
                                actions->conf;
                        uint16_t n;
 
+                       if (!rss || !rss->num) {
+                               rte_flow_error_set(error, EINVAL,
+                                                  RTE_FLOW_ERROR_TYPE_ACTION,
+                                                  actions,
+                                                  "no valid queues");
+                               return -rte_errno;
+                       }
                        if (action->queues_n == 1) {
                                uint16_t found = 0;
 
@@ -524,6 +537,16 @@ priv_flow_validate(struct priv *priv,
                                        return -rte_errno;
                                }
                        }
+                       for (n = 0; n < rss->num; ++n) {
+                               if (rss->queue[n] >= priv->rxqs_n) {
+                                       rte_flow_error_set(error, EINVAL,
+                                                  RTE_FLOW_ERROR_TYPE_ACTION,
+                                                  actions,
+                                                  "queue id > number of"
+                                                  " queues");
+                                       return -rte_errno;
+                               }
+                       }
                        action->queue = 1;
                        for (n = 0; n < rss->num; ++n)
                                action->queues[n] = rss->queue[n];
@@ -557,6 +580,10 @@ priv_flow_validate(struct priv *priv,
        }
        if (action->mark && !flow->ibv_attr && !action->drop)
                flow->offset += sizeof(struct ibv_exp_flow_spec_action_tag);
+#ifdef HAVE_VERBS_IBV_EXP_FLOW_SPEC_ACTION_DROP
+       if (!flow->ibv_attr && action->drop)
+               flow->offset += sizeof(struct ibv_exp_flow_spec_action_drop);
+#endif
        if (!action->queue && !action->drop) {
                rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
                                   NULL, "no valid action");
@@ -759,6 +786,7 @@ mlx5_flow_create_ipv6(const struct rte_flow_item *item,
        struct mlx5_flow *flow = (struct mlx5_flow *)data;
        struct ibv_exp_flow_spec_ipv6_ext *ipv6;
        unsigned int ipv6_size = sizeof(struct ibv_exp_flow_spec_ipv6_ext);
+       unsigned int i;
 
        ++flow->ibv_attr->num_of_specs;
        flow->ibv_attr->priority = 1;
@@ -784,6 +812,11 @@ mlx5_flow_create_ipv6(const struct rte_flow_item *item,
        ipv6->mask.flow_label = mask->hdr.vtc_flow;
        ipv6->mask.next_hdr = mask->hdr.proto;
        ipv6->mask.hop_limit = mask->hdr.hop_limits;
+       /* Remove unwanted bits from values. */
+       for (i = 0; i < RTE_DIM(ipv6->val.src_ip); ++i) {
+               ipv6->val.src_ip[i] &= ipv6->mask.src_ip[i];
+               ipv6->val.dst_ip[i] &= ipv6->mask.dst_ip[i];
+       }
        ipv6->val.flow_label &= ipv6->mask.flow_label;
        ipv6->val.next_hdr &= ipv6->mask.next_hdr;
        ipv6->val.hop_limit &= ipv6->mask.hop_limit;
@@ -968,6 +1001,10 @@ priv_flow_create_action_queue_drop(struct priv *priv,
                                   struct rte_flow_error *error)
 {
        struct rte_flow *rte_flow;
+#ifdef HAVE_VERBS_IBV_EXP_FLOW_SPEC_ACTION_DROP
+       struct ibv_exp_flow_spec_action_drop *drop;
+       unsigned int size = sizeof(struct ibv_exp_flow_spec_action_drop);
+#endif
 
        assert(priv->pd);
        assert(priv->ctx);
@@ -978,10 +1015,19 @@ priv_flow_create_action_queue_drop(struct priv *priv,
                return NULL;
        }
        rte_flow->drop = 1;
+#ifdef HAVE_VERBS_IBV_EXP_FLOW_SPEC_ACTION_DROP
+       drop = (void *)((uintptr_t)flow->ibv_attr + flow->offset);
+       *drop = (struct ibv_exp_flow_spec_action_drop){
+                       .type = IBV_EXP_FLOW_SPEC_ACTION_DROP,
+                       .size = size,
+       };
+       ++flow->ibv_attr->num_of_specs;
+       flow->offset += sizeof(struct ibv_exp_flow_spec_action_drop);
+#endif
        rte_flow->ibv_attr = flow->ibv_attr;
-       rte_flow->qp = priv->flow_drop_queue->qp;
        if (!priv->started)
                return rte_flow;
+       rte_flow->qp = priv->flow_drop_queue->qp;
        rte_flow->ibv_flow = ibv_exp_create_flow(rte_flow->qp,
                                                 rte_flow->ibv_attr);
        if (!rte_flow->ibv_flow) {
@@ -1026,24 +1072,20 @@ priv_flow_create_action_queue(struct priv *priv,
        assert(priv->pd);
        assert(priv->ctx);
        assert(!action->drop);
-       rte_flow = rte_calloc(__func__, 1,
-                             sizeof(*rte_flow) + sizeof(struct rxq *) *
-                             action->queues_n, 0);
+       rte_flow = rte_calloc(__func__, 1, sizeof(*rte_flow) +
+                             sizeof(*rte_flow->rxqs) * action->queues_n, 0);
        if (!rte_flow) {
                rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
                                   NULL, "cannot allocate flow memory");
                return NULL;
        }
-       rte_flow->rxqs = (struct rxq *(*)[])((uintptr_t)rte_flow +
-                                            sizeof(struct rxq *) *
-                                            action->queues_n);
        for (i = 0; i < action->queues_n; ++i) {
                struct rxq_ctrl *rxq;
 
                rxq = container_of((*priv->rxqs)[action->queues[i]],
                                   struct rxq_ctrl, rxq);
                wqs[i] = rxq->wq;
-               (*rte_flow->rxqs)[i] = &rxq->rxq;
+               rte_flow->rxqs[i] = &rxq->rxq;
                ++rte_flow->rxqs_n;
                rxq->rxq.mark |= action->mark;
        }
@@ -1209,7 +1251,7 @@ mlx5_flow_create(struct rte_eth_dev *dev,
        priv_lock(priv);
        flow = priv_flow_create(priv, attr, items, actions, error);
        if (flow) {
-               LIST_INSERT_HEAD(&priv->flows, flow, next);
+               TAILQ_INSERT_TAIL(&priv->flows, flow, next);
                DEBUG("Flow created %p", (void *)flow);
        }
        priv_unlock(priv);
@@ -1228,8 +1270,7 @@ static void
 priv_flow_destroy(struct priv *priv,
                  struct rte_flow *flow)
 {
-       (void)priv;
-       LIST_REMOVE(flow, next);
+       TAILQ_REMOVE(&priv->flows, flow, next);
        if (flow->ibv_flow)
                claim_zero(ibv_exp_destroy_flow(flow->ibv_flow));
        if (flow->drop)
@@ -1253,10 +1294,10 @@ priv_flow_destroy(struct priv *priv,
                 * present in any other marked flow (RSS or not).
                 */
                for (queue_n = 0; queue_n < flow->rxqs_n; ++queue_n) {
-                       rxq = (*flow->rxqs)[queue_n];
-                       for (tmp = LIST_FIRST(&priv->flows);
+                       rxq = flow->rxqs[queue_n];
+                       for (tmp = TAILQ_FIRST(&priv->flows);
                             tmp;
-                            tmp = LIST_NEXT(tmp, next)) {
+                            tmp = TAILQ_NEXT(tmp, next)) {
                                uint32_t tqueue_n;
 
                                if (tmp->drop)
@@ -1266,7 +1307,7 @@ priv_flow_destroy(struct priv *priv,
                                     ++tqueue_n) {
                                        struct rxq *trxq;
 
-                                       trxq = (*tmp->rxqs)[tqueue_n];
+                                       trxq = tmp->rxqs[tqueue_n];
                                        if (rxq == trxq)
                                                ++mark_n;
                                }
@@ -1309,10 +1350,10 @@ mlx5_flow_destroy(struct rte_eth_dev *dev,
 static void
 priv_flow_flush(struct priv *priv)
 {
-       while (!LIST_EMPTY(&priv->flows)) {
+       while (!TAILQ_EMPTY(&priv->flows)) {
                struct rte_flow *flow;
 
-               flow = LIST_FIRST(&priv->flows);
+               flow = TAILQ_FIRST(&priv->flows);
                priv_flow_destroy(priv, flow);
        }
 }
@@ -1444,13 +1485,18 @@ priv_flow_delete_drop_queue(struct priv *priv)
        struct rte_flow_drop *fdq = priv->flow_drop_queue;
        unsigned int i;
 
-       claim_zero(ibv_destroy_qp(fdq->qp));
-       claim_zero(ibv_exp_destroy_rwq_ind_table(fdq->ind_table));
+       if (!fdq)
+               return;
+       if (fdq->qp)
+               claim_zero(ibv_destroy_qp(fdq->qp));
+       if (fdq->ind_table)
+               claim_zero(ibv_exp_destroy_rwq_ind_table(fdq->ind_table));
        for (i = 0; i != MLX5_DROP_WQ_N; ++i) {
-               assert(fdq->wqs[i]);
-               claim_zero(ibv_exp_destroy_wq(fdq->wqs[i]));
+               if (fdq->wqs[i])
+                       claim_zero(ibv_exp_destroy_wq(fdq->wqs[i]));
        }
-       claim_zero(ibv_destroy_cq(fdq->cq));
+       if (fdq->cq)
+               claim_zero(ibv_destroy_cq(fdq->cq));
        rte_free(fdq);
        priv->flow_drop_queue = NULL;
 }
@@ -1468,16 +1514,14 @@ priv_flow_stop(struct priv *priv)
 {
        struct rte_flow *flow;
 
-       for (flow = LIST_FIRST(&priv->flows);
-            flow;
-            flow = LIST_NEXT(flow, next)) {
+       TAILQ_FOREACH_REVERSE(flow, &priv->flows, mlx5_flows, next) {
                claim_zero(ibv_exp_destroy_flow(flow->ibv_flow));
                flow->ibv_flow = NULL;
                if (flow->mark) {
                        unsigned int n;
 
                        for (n = 0; n < flow->rxqs_n; ++n)
-                               (*flow->rxqs)[n]->mark = 0;
+                               flow->rxqs[n]->mark = 0;
                }
                DEBUG("Flow %p removed", (void *)flow);
        }
@@ -1502,9 +1546,7 @@ priv_flow_start(struct priv *priv)
        ret = priv_flow_create_drop_queue(priv);
        if (ret)
                return -1;
-       for (flow = LIST_FIRST(&priv->flows);
-            flow;
-            flow = LIST_NEXT(flow, next)) {
+       TAILQ_FOREACH(flow, &priv->flows, next) {
                struct ibv_qp *qp;
 
                if (flow->drop)
@@ -1522,8 +1564,66 @@ priv_flow_start(struct priv *priv)
                        unsigned int n;
 
                        for (n = 0; n < flow->rxqs_n; ++n)
-                               (*flow->rxqs)[n]->mark = 1;
+                               flow->rxqs[n]->mark = 1;
+               }
+       }
+       return 0;
+}
+
+/**
+ * Verify if the Rx queue is used in a flow.
+ *
+ * @param priv
+ *   Pointer to private structure.
+ * @param rxq
+ *   Pointer to the queue to search.
+ *
+ * @return
+ *   Nonzero if the queue is used by a flow.
+ */
+int
+priv_flow_rxq_in_use(struct priv *priv, struct rxq *rxq)
+{
+       struct rte_flow *flow;
+
+       for (flow = TAILQ_FIRST(&priv->flows);
+            flow;
+            flow = TAILQ_NEXT(flow, next)) {
+               unsigned int n;
+
+               if (flow->drop)
+                       continue;
+               for (n = 0; n < flow->rxqs_n; ++n) {
+                       if (flow->rxqs[n] == rxq)
+                               return 1;
                }
        }
        return 0;
 }
+
+/**
+ * Isolated mode.
+ *
+ * @see rte_flow_isolate()
+ * @see rte_flow_ops
+ */
+int
+mlx5_flow_isolate(struct rte_eth_dev *dev,
+                 int enable,
+                 struct rte_flow_error *error)
+{
+       struct priv *priv = dev->data->dev_private;
+
+       priv_lock(priv);
+       if (priv->started) {
+               rte_flow_error_set(error, EBUSY,
+                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                  NULL,
+                                  "port must be stopped first");
+               priv_unlock(priv);
+               return -rte_errno;
+       }
+       priv->isolated = !!enable;
+       priv_unlock(priv);
+       return 0;
+}