ethdev: move egress metadata to dynamic field
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_dv.c
index 13178cc..42c265f 100644 (file)
@@ -212,6 +212,33 @@ flow_d_shared_unlock(struct rte_eth_dev *dev)
        }
 }
 
+/* Update VLAN's VID/PCP based on input rte_flow_action.
+ *
+ * @param[in] action
+ *   Pointer to struct rte_flow_action.
+ * @param[out] vlan
+ *   Pointer to struct rte_vlan_hdr.
+ */
+static void
+mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action,
+                        struct rte_vlan_hdr *vlan)
+{
+       uint16_t vlan_tci;
+       if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) {
+               vlan_tci =
+                   ((const struct rte_flow_action_of_set_vlan_pcp *)
+                                              action->conf)->vlan_pcp;
+               vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT;
+               vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
+               vlan->vlan_tci |= vlan_tci;
+       } else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) {
+               vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
+               vlan->vlan_tci |= rte_be_to_cpu_16
+                   (((const struct rte_flow_action_of_set_vlan_vid *)
+                                            action->conf)->vlan_vid);
+       }
+}
+
 /**
  * Convert modify-header action to DV specification.
  *
@@ -793,7 +820,7 @@ flow_dv_convert_action_set_reg
  *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
 static int
-flow_dv_validate_item_meta(struct rte_eth_dev *dev,
+flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused,
                           const struct rte_flow_item *item,
                           const struct rte_flow_attr *attr,
                           struct rte_flow_error *error)
@@ -801,17 +828,10 @@ flow_dv_validate_item_meta(struct rte_eth_dev *dev,
        const struct rte_flow_item_meta *spec = item->spec;
        const struct rte_flow_item_meta *mask = item->mask;
        const struct rte_flow_item_meta nic_mask = {
-               .data = RTE_BE32(UINT32_MAX)
+               .data = UINT32_MAX
        };
        int ret;
-       uint64_t offloads = dev->data->dev_conf.txmode.offloads;
 
-       if (!(offloads & DEV_TX_OFFLOAD_MATCH_METADATA))
-               return rte_flow_error_set(error, EPERM,
-                                         RTE_FLOW_ERROR_TYPE_ITEM,
-                                         NULL,
-                                         "match on metadata offload "
-                                         "configuration is off for this port");
        if (!spec)
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
@@ -973,6 +993,11 @@ flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev,
                                          NULL,
                                          "cannot pop vlan without a "
                                          "match on (outer) vlan in the flow");
+       if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
+                                         "wrong action order, port_id should "
+                                         "be after pop VLAN action");
        return 0;
 }
 
@@ -1050,6 +1075,7 @@ flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items,
  */
 static int
 flow_dv_validate_action_push_vlan(uint64_t action_flags,
+                                 uint64_t item_flags,
                                  const struct rte_flow_action *action,
                                  const struct rte_flow_attr *attr,
                                  struct rte_flow_error *error)
@@ -1067,6 +1093,19 @@ flow_dv_validate_action_push_vlan(uint64_t action_flags,
                                          RTE_FLOW_ERROR_TYPE_ACTION, action,
                                          "no support for multiple VLAN "
                                          "actions");
+       if (!mlx5_flow_find_action
+                       (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) &&
+           !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
+               return rte_flow_error_set(error, ENOTSUP,
+                               RTE_FLOW_ERROR_TYPE_ACTION, action,
+                               "push VLAN needs to match on VLAN in order to "
+                               "get VLAN VID information because there is "
+                               "no followed set VLAN VID action");
+       if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
+                                         "wrong action order, port_id should "
+                                         "be after push VLAN");
        (void)attr;
        return 0;
 }
@@ -1098,17 +1137,21 @@ flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags,
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION, action,
                                          "VLAN PCP value is too big");
-       if (mlx5_flow_find_action(actions,
-                                 RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN) == NULL)
+       if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN))
                return rte_flow_error_set(error, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_ACTION, action,
-                                         "set VLAN PCP can only be used "
-                                         "with push VLAN action");
-       if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
+                                         "set VLAN PCP action must follow "
+                                         "the push VLAN action");
+       if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
                return rte_flow_error_set(error, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_ACTION, action,
-                                         "set VLAN PCP action must precede "
-                                         "the push VLAN action");
+                                         "Multiple VLAN PCP modification are "
+                                         "not supported");
+       if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
+                                         "wrong action order, port_id should "
+                                         "be after set VLAN PCP");
        return 0;
 }
 
@@ -1129,6 +1172,7 @@ flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags,
  */
 static int
 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
+                                    uint64_t action_flags,
                                     const struct rte_flow_action actions[],
                                     struct rte_flow_error *error)
 {
@@ -1139,18 +1183,24 @@ flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION, action,
                                          "VLAN VID value is too big");
-       /* If a push VLAN action follows then it will handle this action */
-       if (mlx5_flow_find_action(actions,
-                                 RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN))
-               return 0;
+       /* there is an of_push_vlan action before us */
+       if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) {
+               if (mlx5_flow_find_action(actions + 1,
+                                         RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID))
+                       return rte_flow_error_set(error, ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, action,
+                                       "Multiple VLAN VID modifications are "
+                                       "not supported");
+               else
+                       return 0;
+       }
 
        /*
         * Action is on an existing VLAN header:
         *    Need to verify this is a single modify CID action.
         *   Rule mast include a match on outer VLAN.
         */
-       if (mlx5_flow_find_action(++action,
-                                 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID))
+       if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID)
                return rte_flow_error_set(error, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_ACTION, action,
                                          "Multiple VLAN VID modifications are "
@@ -1160,6 +1210,11 @@ flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
                                          RTE_FLOW_ERROR_TYPE_ACTION, action,
                                          "match on VLAN is required in order "
                                          "to set VLAN VID");
+       if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
+                                         "wrong action order, port_id should "
+                                         "be after set VLAN VID");
        return 0;
 }
 
@@ -3622,6 +3677,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                        break;
                case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
                        ret = flow_dv_validate_action_push_vlan(action_flags,
+                                                               item_flags,
                                                                actions, attr,
                                                                error);
                        if (ret < 0)
@@ -3635,13 +3691,16 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                        if (ret < 0)
                                return ret;
                        /* Count PCP with push_vlan command. */
+                       action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP;
                        break;
                case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
                        ret = flow_dv_validate_action_set_vlan_vid
-                                               (item_flags, actions, error);
+                                               (item_flags, action_flags,
+                                                actions, error);
                        if (ret < 0)
                                return ret;
                        /* Count VID with push_vlan command. */
+                       action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
                        break;
                case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
                case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
@@ -4750,10 +4809,10 @@ flow_dv_translate_item_meta(void *matcher, void *key,
                meta_m = &rte_flow_item_meta_mask;
        meta_v = (const void *)item->spec;
        if (meta_v) {
-               MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a,
-                        rte_be_to_cpu_32(meta_m->data));
-               MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a,
-                        rte_be_to_cpu_32(meta_v->data & meta_m->data));
+               MLX5_SET(fte_match_set_misc2, misc2_m,
+                        metadata_reg_a, meta_m->data);
+               MLX5_SET(fte_match_set_misc2, misc2_v,
+                        metadata_reg_a, meta_v->data & meta_m->data);
        }
 }
 
@@ -5474,8 +5533,6 @@ flow_dv_translate(struct rte_eth_dev *dev,
        void *match_value = dev_flow->dv.value.buf;
        uint8_t next_protocol = 0xff;
        struct rte_vlan_hdr vlan = { 0 };
-       bool vlan_inherited = false;
-       uint16_t vlan_tci;
        uint32_t table;
        int ret = 0;
 
@@ -5500,6 +5557,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
                uint32_t port_id = 0;
                struct mlx5_flow_dv_port_id_action_resource port_id_resource;
                int action_type = actions->type;
+               const struct rte_flow_action *found_action = NULL;
 
                switch (action_type) {
                case RTE_FLOW_ACTION_TYPE_VOID:
@@ -5598,49 +5656,36 @@ cnt_err:
                        action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
                        break;
                case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
-                       if (!vlan_inherited) {
-                               flow_dev_get_vlan_info_from_items(items, &vlan);
-                               vlan_inherited = true;
-                       }
+                       flow_dev_get_vlan_info_from_items(items, &vlan);
                        vlan.eth_proto = rte_be_to_cpu_16
                             ((((const struct rte_flow_action_of_push_vlan *)
                                                   actions->conf)->ethertype));
+                       found_action = mlx5_flow_find_action
+                                       (actions + 1,
+                                        RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID);
+                       if (found_action)
+                               mlx5_update_vlan_vid_pcp(found_action, &vlan);
+                       found_action = mlx5_flow_find_action
+                                       (actions + 1,
+                                        RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP);
+                       if (found_action)
+                               mlx5_update_vlan_vid_pcp(found_action, &vlan);
                        if (flow_dv_create_action_push_vlan
                                            (dev, attr, &vlan, dev_flow, error))
                                return -rte_errno;
                        dev_flow->dv.actions[actions_n++] =
                                           dev_flow->dv.push_vlan_res->action;
                        action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
-                       /* Push VLAN command is also handling this VLAN_VID */
-                       action_flags &= ~MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
                        break;
                case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
-                       if (!vlan_inherited) {
-                               flow_dev_get_vlan_info_from_items(items, &vlan);
-                               vlan_inherited = true;
-                       }
-                       vlan_tci =
-                           ((const struct rte_flow_action_of_set_vlan_pcp *)
-                                                      actions->conf)->vlan_pcp;
-                       vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT;
-                       vlan.vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
-                       vlan.vlan_tci |= vlan_tci;
-                       /* Push VLAN command will use this value */
+                       /* of_vlan_push action handled this action */
+                       assert(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN);
                        break;
                case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
-                       if (!vlan_inherited) {
-                               flow_dev_get_vlan_info_from_items(items, &vlan);
-                               vlan_inherited = true;
-                       }
-                       vlan.vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
-                       vlan.vlan_tci |= rte_be_to_cpu_16
-                           (((const struct rte_flow_action_of_set_vlan_vid *)
-                                                    actions->conf)->vlan_vid);
-                       /* Push VLAN command will use this value */
-                       if (mlx5_flow_find_action
-                               (actions,
-                                RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN))
+                       if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
                                break;
+                       flow_dev_get_vlan_info_from_items(items, &vlan);
+                       mlx5_update_vlan_vid_pcp(actions, &vlan);
                        /* If no VLAN push - this is a modify header action */
                        if (flow_dv_convert_action_modify_vlan_vid
                                                        (&res, actions, error))
@@ -5843,7 +5888,7 @@ cnt_err:
                        modify_action_position = actions_n++;
        }
        dev_flow->dv.actions_n = actions_n;
-       flow->actions = action_flags;
+       dev_flow->actions = action_flags;
        for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
                int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
                int item_type = items->type;
@@ -6070,7 +6115,7 @@ flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
        LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
                dv = &dev_flow->dv;
                n = dv->actions_n;
-               if (flow->actions & MLX5_FLOW_ACTION_DROP) {
+               if (dev_flow->actions & MLX5_FLOW_ACTION_DROP) {
                        if (flow->transfer) {
                                dv->actions[n++] = priv->sh->esw_drop_action;
                        } else {
@@ -6085,7 +6130,7 @@ flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
                                }
                                dv->actions[n++] = dv->hrxq->action;
                        }
-               } else if (flow->actions &
+               } else if (dev_flow->actions &
                           (MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)) {
                        struct mlx5_hrxq *hrxq;
 
@@ -6141,7 +6186,7 @@ error:
        LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
                struct mlx5_flow_dv *dv = &dev_flow->dv;
                if (dv->hrxq) {
-                       if (flow->actions & MLX5_FLOW_ACTION_DROP)
+                       if (dev_flow->actions & MLX5_FLOW_ACTION_DROP)
                                mlx5_hrxq_drop_release(dev);
                        else
                                mlx5_hrxq_release(dev, dv->hrxq);
@@ -6375,7 +6420,7 @@ flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
                        dv->flow = NULL;
                }
                if (dv->hrxq) {
-                       if (flow->actions & MLX5_FLOW_ACTION_DROP)
+                       if (dev_flow->actions & MLX5_FLOW_ACTION_DROP)
                                mlx5_hrxq_drop_release(dev);
                        else
                                mlx5_hrxq_release(dev, dv->hrxq);