net/mlx5: fix IPv6 flow pattern item
[dpdk.git] / drivers / net / mlx5 / mlx5_flow.c
index 5468642..cd3e5da 100644 (file)
@@ -98,11 +98,11 @@ struct rte_flow {
        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. */
@@ -377,6 +377,8 @@ mlx5_flow_item_validate(const struct rte_flow_item *item,
  *   Perform verbose error reporting if not NULL.
  * @param[in, out] flow
  *   Flow structure to update.
+ * @param[in, out] action
+ *   Action structure to update.
  *
  * @return
  *   0 on success, a negative errno value otherwise and rte_errno is set.
@@ -387,14 +389,10 @@ priv_flow_validate(struct priv *priv,
                   const struct rte_flow_item items[],
                   const struct rte_flow_action actions[],
                   struct rte_flow_error *error,
-                  struct mlx5_flow *flow)
+                  struct mlx5_flow *flow,
+                  struct mlx5_flow_action *action)
 {
        const struct mlx5_flow_items *cur_item = mlx5_flow_items;
-       struct mlx5_flow_action action = {
-               .queue = 0,
-               .drop = 0,
-               .mark = 0,
-       };
 
        (void)priv;
        if (attr->group) {
@@ -474,7 +472,7 @@ priv_flow_validate(struct priv *priv,
                if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) {
                        continue;
                } else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
-                       action.drop = 1;
+                       action->drop = 1;
                } else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
                        const struct rte_flow_action_queue *queue =
                                (const struct rte_flow_action_queue *)
@@ -484,34 +482,44 @@ priv_flow_validate(struct priv *priv,
 
                        if (!queue || (queue->index > (priv->rxqs_n - 1)))
                                goto exit_action_not_supported;
-                       for (n = 0; n < action.queues_n; ++n) {
-                               if (action.queues[n] == queue->index) {
+                       for (n = 0; n < action->queues_n; ++n) {
+                               if (action->queues[n] == queue->index) {
                                        found = 1;
                                        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 (action.queues_n == 1) {
+                       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;
 
-                               assert(action.queues_n);
+                               assert(action->queues_n);
                                for (n = 0; n < rss->num; ++n) {
-                                       if (action.queues[0] == rss->queue[n]) {
+                                       if (action->queues[0] ==
+                                           rss->queue[n]) {
                                                found = 1;
                                                break;
                                        }
@@ -525,10 +533,20 @@ priv_flow_validate(struct priv *priv,
                                        return -rte_errno;
                                }
                        }
-                       action.queue = 1;
+                       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];
-                       action.queues_n = rss->num;
+                               action->queues[n] = rss->queue[n];
+                       action->queues_n = rss->num;
                } else if (actions->type == RTE_FLOW_ACTION_TYPE_MARK) {
                        const struct rte_flow_action_mark *mark =
                                (const struct rte_flow_action_mark *)
@@ -548,16 +566,17 @@ priv_flow_validate(struct priv *priv,
                                                   " and 16777199");
                                return -rte_errno;
                        }
-                       action.mark = 1;
+                       action->mark = 1;
+                       action->mark_id = mark->id;
                } else if (actions->type == RTE_FLOW_ACTION_TYPE_FLAG) {
-                       action.mark = 1;
+                       action->mark = 1;
                } else {
                        goto exit_action_not_supported;
                }
        }
-       if (action.mark && !flow->ibv_attr && !action.drop)
+       if (action->mark && !flow->ibv_attr && !action->drop)
                flow->offset += sizeof(struct ibv_exp_flow_spec_action_tag);
-       if (!action.queue && !action.drop) {
+       if (!action->queue && !action->drop) {
                rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
                                   NULL, "no valid action");
                return -rte_errno;
@@ -589,9 +608,17 @@ mlx5_flow_validate(struct rte_eth_dev *dev,
        struct priv *priv = dev->data->dev_private;
        int ret;
        struct mlx5_flow flow = { .offset = sizeof(struct ibv_exp_flow_attr) };
+       struct mlx5_flow_action action = {
+               .queue = 0,
+               .drop = 0,
+               .mark = 0,
+               .mark_id = MLX5_FLOW_MARK_DEFAULT,
+               .queues_n = 0,
+       };
 
        priv_lock(priv);
-       ret = priv_flow_validate(priv, attr, items, actions, error, &flow);
+       ret = priv_flow_validate(priv, attr, items, actions, error, &flow,
+                                &action);
        priv_unlock(priv);
        return ret;
 }
@@ -751,6 +778,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;
@@ -776,6 +804,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;
@@ -1018,24 +1051,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;
        }
@@ -1130,11 +1159,18 @@ priv_flow_create(struct priv *priv,
                 struct rte_flow_error *error)
 {
        struct rte_flow *rte_flow;
-       struct mlx5_flow_action action;
        struct mlx5_flow flow = { .offset = sizeof(struct ibv_exp_flow_attr), };
+       struct mlx5_flow_action action = {
+               .queue = 0,
+               .drop = 0,
+               .mark = 0,
+               .mark_id = MLX5_FLOW_MARK_DEFAULT,
+               .queues_n = 0,
+       };
        int err;
 
-       err = priv_flow_validate(priv, attr, items, actions, error, &flow);
+       err = priv_flow_validate(priv, attr, items, actions, error, &flow,
+                                &action);
        if (err)
                goto exit;
        flow.ibv_attr = rte_malloc(__func__, flow.offset, 0);
@@ -1156,52 +1192,8 @@ priv_flow_create(struct priv *priv,
        flow.inner = 0;
        flow.hash_fields = 0;
        claim_zero(priv_flow_validate(priv, attr, items, actions,
-                                     error, &flow));
-       action = (struct mlx5_flow_action){
-               .queue = 0,
-               .drop = 0,
-               .mark = 0,
-               .mark_id = MLX5_FLOW_MARK_DEFAULT,
-       };
-       for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
-               if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) {
-                       continue;
-               } else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
-                       action.queue = 1;
-                       action.queues[action.queues_n++] =
-                               ((const struct rte_flow_action_queue *)
-                                actions->conf)->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;
-
-                       action.queue = 1;
-                       action.queues_n = rss->num;
-                       for (n = 0; n < rss->num; ++n)
-                               action.queues[n] = rss->queue[n];
-               } else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
-                       action.drop = 1;
-                       action.mark = 0;
-               } else if (actions->type == RTE_FLOW_ACTION_TYPE_MARK) {
-                       const struct rte_flow_action_mark *mark =
-                               (const struct rte_flow_action_mark *)
-                               actions->conf;
-
-                       if (mark)
-                               action.mark_id = mark->id;
-                       action.mark = !action.drop;
-               } else if (actions->type == RTE_FLOW_ACTION_TYPE_FLAG) {
-                       action.mark = 1;
-               } else {
-                       rte_flow_error_set(error, ENOTSUP,
-                                          RTE_FLOW_ERROR_TYPE_ACTION,
-                                          actions, "unsupported action");
-                       goto exit;
-               }
-       }
-       if (action.mark) {
+                                     error, &flow, &action));
+       if (action.mark && !action.drop) {
                mlx5_flow_create_flag_mark(&flow, action.mark_id);
                flow.offset += sizeof(struct ibv_exp_flow_spec_action_tag);
        }
@@ -1282,7 +1274,7 @@ 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];
+                       rxq = flow->rxqs[queue_n];
                        for (tmp = LIST_FIRST(&priv->flows);
                             tmp;
                             tmp = LIST_NEXT(tmp, next)) {
@@ -1295,7 +1287,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;
                                }
@@ -1506,7 +1498,7 @@ priv_flow_stop(struct priv *priv)
                        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);
        }
@@ -1551,7 +1543,38 @@ 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 = LIST_FIRST(&priv->flows);
+            flow;
+            flow = LIST_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;