New upstream version 18.08
[deb_dpdk.git] / drivers / net / enic / enic_flow.c
index 28923b0..0cf04ae 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <errno.h>
+#include <stdint.h>
 #include <rte_log.h>
 #include <rte_ethdev_driver.h>
 #include <rte_flow_driver.h>
@@ -273,21 +274,33 @@ static const enum rte_flow_action_type enic_supported_actions_v1[] = {
 };
 
 /** Supported actions for newer NICs */
-static const enum rte_flow_action_type enic_supported_actions_v2[] = {
+static const enum rte_flow_action_type enic_supported_actions_v2_id[] = {
        RTE_FLOW_ACTION_TYPE_QUEUE,
        RTE_FLOW_ACTION_TYPE_MARK,
        RTE_FLOW_ACTION_TYPE_FLAG,
        RTE_FLOW_ACTION_TYPE_END,
 };
 
+static const enum rte_flow_action_type enic_supported_actions_v2_drop[] = {
+       RTE_FLOW_ACTION_TYPE_QUEUE,
+       RTE_FLOW_ACTION_TYPE_MARK,
+       RTE_FLOW_ACTION_TYPE_FLAG,
+       RTE_FLOW_ACTION_TYPE_DROP,
+       RTE_FLOW_ACTION_TYPE_END,
+};
+
 /** Action capabilities indexed by NIC version information */
 static const struct enic_action_cap enic_action_cap[] = {
        [FILTER_ACTION_RQ_STEERING_FLAG] = {
                .actions = enic_supported_actions_v1,
                .copy_fn = enic_copy_action_v1,
        },
-       [FILTER_ACTION_V2_ALL] = {
-               .actions = enic_supported_actions_v2,
+       [FILTER_ACTION_FILTER_ID_FLAG] = {
+               .actions = enic_supported_actions_v2_id,
+               .copy_fn = enic_copy_action_v2,
+       },
+       [FILTER_ACTION_DROP_FLAG] = {
+               .actions = enic_supported_actions_v2_drop,
                .copy_fn = enic_copy_action_v2,
        },
 };
@@ -544,16 +557,21 @@ enic_copy_item_vlan_v2(const struct rte_flow_item *item,
        if (!spec)
                return 0;
 
-       /* Don't support filtering in tpid */
-       if (mask) {
-               if (mask->tpid != 0)
-                       return ENOTSUP;
-       } else {
+       if (!mask)
                mask = &rte_flow_item_vlan_mask;
-               RTE_ASSERT(mask->tpid == 0);
-       }
 
        if (*inner_ofst == 0) {
+               struct ether_hdr *eth_mask =
+                       (void *)gp->layer[FILTER_GENERIC_1_L2].mask;
+               struct ether_hdr *eth_val =
+                       (void *)gp->layer[FILTER_GENERIC_1_L2].val;
+
+               /* Outer TPID cannot be matched */
+               if (eth_mask->ether_type)
+                       return ENOTSUP;
+               eth_mask->ether_type = mask->inner_type;
+               eth_val->ether_type = spec->inner_type;
+
                /* Outer header. Use the vlan mask/val fields */
                gp->mask_vlan = mask->tci;
                gp->val_vlan = spec->tci;
@@ -952,6 +970,9 @@ static int
 enic_copy_action_v1(const struct rte_flow_action actions[],
                    struct filter_action_v2 *enic_action)
 {
+       enum { FATE = 1, };
+       uint32_t overlap = 0;
+
        FLOW_TRACE();
 
        for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
@@ -963,6 +984,10 @@ enic_copy_action_v1(const struct rte_flow_action actions[],
                        const struct rte_flow_action_queue *queue =
                                (const struct rte_flow_action_queue *)
                                actions->conf;
+
+                       if (overlap & FATE)
+                               return ENOTSUP;
+                       overlap |= FATE;
                        enic_action->rq_idx =
                                enic_rte_rq_idx_to_sop_idx(queue->index);
                        break;
@@ -972,6 +997,8 @@ enic_copy_action_v1(const struct rte_flow_action actions[],
                        break;
                }
        }
+       if (!(overlap & FATE))
+               return ENOTSUP;
        enic_action->type = FILTER_ACTION_RQ_STEERING;
        return 0;
 }
@@ -989,6 +1016,9 @@ static int
 enic_copy_action_v2(const struct rte_flow_action actions[],
                    struct filter_action_v2 *enic_action)
 {
+       enum { FATE = 1, MARK = 2, };
+       uint32_t overlap = 0;
+
        FLOW_TRACE();
 
        for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
@@ -997,6 +1027,10 @@ enic_copy_action_v2(const struct rte_flow_action actions[],
                        const struct rte_flow_action_queue *queue =
                                (const struct rte_flow_action_queue *)
                                actions->conf;
+
+                       if (overlap & FATE)
+                               return ENOTSUP;
+                       overlap |= FATE;
                        enic_action->rq_idx =
                                enic_rte_rq_idx_to_sop_idx(queue->index);
                        enic_action->flags |= FILTER_ACTION_RQ_STEERING_FLAG;
@@ -1007,6 +1041,9 @@ enic_copy_action_v2(const struct rte_flow_action actions[],
                                (const struct rte_flow_action_mark *)
                                actions->conf;
 
+                       if (overlap & MARK)
+                               return ENOTSUP;
+                       overlap |= MARK;
                        /* ENIC_MAGIC_FILTER_ID is reserved and is the highest
                         * in the range of allows mark ids.
                         */
@@ -1017,10 +1054,20 @@ enic_copy_action_v2(const struct rte_flow_action actions[],
                        break;
                }
                case RTE_FLOW_ACTION_TYPE_FLAG: {
+                       if (overlap & MARK)
+                               return ENOTSUP;
+                       overlap |= MARK;
                        enic_action->filter_id = ENIC_MAGIC_FILTER_ID;
                        enic_action->flags |= FILTER_ACTION_FILTER_ID_FLAG;
                        break;
                }
+               case RTE_FLOW_ACTION_TYPE_DROP: {
+                       if (overlap & FATE)
+                               return ENOTSUP;
+                       overlap |= FATE;
+                       enic_action->flags |= FILTER_ACTION_DROP_FLAG;
+                       break;
+               }
                case RTE_FLOW_ACTION_TYPE_VOID:
                        continue;
                default:
@@ -1028,6 +1075,8 @@ enic_copy_action_v2(const struct rte_flow_action actions[],
                        break;
                }
        }
+       if (!(overlap & FATE))
+               return ENOTSUP;
        enic_action->type = FILTER_ACTION_V2;
        return 0;
 }
@@ -1059,10 +1108,14 @@ enic_get_filter_cap(struct enic *enic)
 static const struct enic_action_cap *
 enic_get_action_cap(struct enic *enic)
 {
-       static const struct enic_action_cap *ea;
-
-       if (enic->filter_tags)
-               ea = &enic_action_cap[FILTER_ACTION_V2_ALL];
+       const struct enic_action_cap *ea;
+       uint8_t actions;
+
+       actions = enic->filter_actions;
+       if (actions & FILTER_ACTION_DROP_FLAG)
+               ea = &enic_action_cap[FILTER_ACTION_DROP_FLAG];
+       else if (actions & FILTER_ACTION_FILTER_ID_FLAG)
+               ea = &enic_action_cap[FILTER_ACTION_FILTER_ID_FLAG];
        else
                ea = &enic_action_cap[FILTER_ACTION_RQ_STEERING_FLAG];
        return ea;
@@ -1268,6 +1321,12 @@ enic_flow_parse(struct rte_eth_dev *dev,
                                           NULL,
                                           "egress is not supported");
                        return -rte_errno;
+               } else if (attrs->transfer) {
+                       rte_flow_error_set(error, ENOTSUP,
+                                          RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
+                                          NULL,
+                                          "transfer is not supported");
+                       return -rte_errno;
                } else if (!attrs->ingress) {
                        rte_flow_error_set(error, ENOTSUP,
                                           RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,