common/mlx5: introduce common library
[dpdk.git] / drivers / net / mlx5 / mlx5_flow.c
index 5c78ea7..47ba521 100644 (file)
 #include <rte_malloc.h>
 #include <rte_ip.h>
 
-#include "mlx5.h"
+#include <mlx5_glue.h>
+#include <mlx5_devx_cmds.h>
+#include <mlx5_prm.h>
+
 #include "mlx5_defs.h"
+#include "mlx5.h"
 #include "mlx5_flow.h"
-#include "mlx5_glue.h"
-#include "mlx5_prm.h"
 #include "mlx5_rxtx.h"
 
 /* Dev ops structure defined in mlx5.c */
@@ -236,6 +238,7 @@ static const struct rte_flow_ops mlx5_flow_ops = {
        .flush = mlx5_flow_flush,
        .isolate = mlx5_flow_isolate,
        .query = mlx5_flow_query,
+       .dev_dump = mlx5_flow_dev_dump,
 };
 
 /* Convert FDIR request to Generic flow. */
@@ -318,6 +321,10 @@ static struct mlx5_flow_tunnel_info tunnels_info[] = {
                .tunnel = MLX5_FLOW_LAYER_IPV6_ENCAP,
                .ptype = RTE_PTYPE_TUNNEL_IP,
        },
+       {
+               .tunnel = MLX5_FLOW_LAYER_GTP,
+               .ptype = RTE_PTYPE_TUNNEL_GTPU,
+       },
 };
 
 /**
@@ -336,7 +343,7 @@ static struct mlx5_flow_tunnel_info tunnels_info[] = {
  *   The request register on success, a negative errno
  *   value otherwise and rte_errno is set.
  */
-enum modify_reg
+int
 mlx5_flow_get_reg_id(struct rte_eth_dev *dev,
                     enum mlx5_feature_name feature,
                     uint32_t id,
@@ -345,6 +352,7 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev,
        struct mlx5_priv *priv = dev->data->dev_private;
        struct mlx5_dev_config *config = &priv->config;
        enum modify_reg start_reg;
+       bool skip_mtr_reg = false;
 
        switch (feature) {
        case MLX5_HAIRPIN_RX:
@@ -383,29 +391,36 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev,
                        return REG_C_0;
                }
                break;
-       case MLX5_COPY_MARK:
        case MLX5_MTR_SFX:
                /*
-                * Metadata COPY_MARK register using is in meter suffix sub
-                * flow while with meter. It's safe to share the same register.
+                * If meter color and flow match share one register, flow match
+                * should use the meter color register for match.
                 */
-               return priv->mtr_color_reg != REG_C_2 ? REG_C_2 : REG_C_3;
+               if (priv->mtr_reg_share)
+                       return priv->mtr_color_reg;
+               else
+                       return priv->mtr_color_reg != REG_C_2 ? REG_C_2 :
+                              REG_C_3;
        case MLX5_MTR_COLOR:
                RTE_ASSERT(priv->mtr_color_reg != REG_NONE);
                return priv->mtr_color_reg;
+       case MLX5_COPY_MARK:
+               /*
+                * Metadata COPY_MARK register using is in meter suffix sub
+                * flow while with meter. It's safe to share the same register.
+                */
+               return priv->mtr_color_reg != REG_C_2 ? REG_C_2 : REG_C_3;
        case MLX5_APP_TAG:
                /*
-                * If meter is enable, it will engage two registers for color
+                * If meter is enable, it will engage the register for color
                 * match and flow match. If meter color match is not using the
                 * REG_C_2, need to skip the REG_C_x be used by meter color
                 * match.
                 * If meter is disable, free to use all available registers.
                 */
-               if (priv->mtr_color_reg != REG_NONE)
-                       start_reg = priv->mtr_color_reg != REG_C_2 ? REG_C_3 :
-                                   REG_C_4;
-               else
-                       start_reg = REG_C_2;
+               start_reg = priv->mtr_color_reg != REG_C_2 ? REG_C_2 :
+                           (priv->mtr_reg_share ? REG_C_3 : REG_C_4);
+               skip_mtr_reg = !!(priv->mtr_en && start_reg == REG_C_2);
                if (id > (REG_C_7 - start_reg))
                        return rte_flow_error_set(error, EINVAL,
                                                  RTE_FLOW_ERROR_TYPE_ITEM,
@@ -420,12 +435,12 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev,
                 * If the available index REG_C_y >= REG_C_x, skip the
                 * color register.
                 */
-               if (start_reg == REG_C_3 && config->flow_mreg_c
-                   [id + REG_C_3 - REG_C_0] >= priv->mtr_color_reg) {
-                       if (config->flow_mreg_c[id + 1 + REG_C_3 - REG_C_0] !=
-                           REG_NONE)
+               if (skip_mtr_reg && config->flow_mreg_c
+                   [id + start_reg - REG_C_0] >= priv->mtr_color_reg) {
+                       if (config->flow_mreg_c
+                           [id + 1 + start_reg - REG_C_0] != REG_NONE)
                                return config->flow_mreg_c
-                                               [id + 1 + REG_C_3 - REG_C_0];
+                                              [id + 1 + start_reg - REG_C_0];
                        return rte_flow_error_set(error, ENOTSUP,
                                                  RTE_FLOW_ERROR_TYPE_ITEM,
                                                  NULL, "unsupported tag id");
@@ -900,11 +915,6 @@ mlx5_flow_validate_action_flag(uint64_t action_flags,
                               const struct rte_flow_attr *attr,
                               struct rte_flow_error *error)
 {
-
-       if (action_flags & MLX5_FLOW_ACTION_DROP)
-               return rte_flow_error_set(error, EINVAL,
-                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
-                                         "can't drop and flag in same flow");
        if (action_flags & MLX5_FLOW_ACTION_MARK)
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
@@ -956,10 +966,6 @@ mlx5_flow_validate_action_mark(const struct rte_flow_action *action,
                                          &mark->id,
                                          "mark id must in 0 <= id < "
                                          RTE_STR(MLX5_FLOW_MARK_MAX));
-       if (action_flags & MLX5_FLOW_ACTION_DROP)
-               return rte_flow_error_set(error, EINVAL,
-                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
-                                         "can't drop and mark in same flow");
        if (action_flags & MLX5_FLOW_ACTION_FLAG)
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
@@ -991,24 +997,10 @@ mlx5_flow_validate_action_mark(const struct rte_flow_action *action,
  *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
 int
-mlx5_flow_validate_action_drop(uint64_t action_flags,
+mlx5_flow_validate_action_drop(uint64_t action_flags __rte_unused,
                               const struct rte_flow_attr *attr,
                               struct rte_flow_error *error)
 {
-       if (action_flags & MLX5_FLOW_ACTION_FLAG)
-               return rte_flow_error_set(error, EINVAL,
-                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
-                                         "can't drop and flag in same flow");
-       if (action_flags & MLX5_FLOW_ACTION_MARK)
-               return rte_flow_error_set(error, EINVAL,
-                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
-                                         "can't drop and mark in same flow");
-       if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
-                           MLX5_FLOW_FATE_ESWITCH_ACTIONS))
-               return rte_flow_error_set(error, EINVAL,
-                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
-                                         "can't have 2 fate actions in"
-                                         " same flow");
        if (attr->egress)
                return rte_flow_error_set(error, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, NULL,
@@ -1150,6 +1142,18 @@ mlx5_flow_validate_action_rss(const struct rte_flow_action *action,
                                          &rss->types,
                                          "some RSS protocols are not"
                                          " supported");
+       if ((rss->types & (ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY)) &&
+           !(rss->types & ETH_RSS_IP))
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
+                                         "L3 partial RSS requested but L3 RSS"
+                                         " type not specified");
+       if ((rss->types & (ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY)) &&
+           !(rss->types & (ETH_RSS_UDP | ETH_RSS_TCP)))
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
+                                         "L4 partial RSS requested but L4 RSS"
+                                         " type not specified");
        if (!priv->rxqs_n)
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION_CONF,
@@ -2947,16 +2951,16 @@ flow_mreg_add_copy_action(struct rte_eth_dev *dev, uint32_t mark_id,
        mcp_res = (void *)mlx5_hlist_lookup(priv->mreg_cp_tbl, mark_id);
        if (mcp_res) {
                /* For non-default rule. */
-               if (mark_id)
+               if (mark_id != MLX5_DEFAULT_COPY_ID)
                        mcp_res->refcnt++;
-               assert(mark_id || mcp_res->refcnt == 1);
+               assert(mark_id != MLX5_DEFAULT_COPY_ID || mcp_res->refcnt == 1);
                return mcp_res;
        }
        /* Provide the full width of FLAG specific value. */
        if (mark_id == (priv->sh->dv_regc0_mask & MLX5_FLOW_MARK_DEFAULT))
                tag_spec.data = MLX5_FLOW_MARK_DEFAULT;
        /* Build a new flow. */
-       if (mark_id) {
+       if (mark_id != MLX5_DEFAULT_COPY_ID) {
                items[0] = (struct rte_flow_item){
                        .type = MLX5_RTE_FLOW_ITEM_TYPE_TAG,
                        .spec = &tag_spec,
@@ -3054,7 +3058,7 @@ flow_mreg_del_copy_action(struct rte_eth_dev *dev,
        }
        /*
         * We do not check availability of metadata registers here,
-        * because copy resources are allocated in this case.
+        * because copy resources are not allocated in this case.
         */
        if (--mcp_res->refcnt)
                return;
@@ -3133,7 +3137,8 @@ flow_mreg_del_default_copy_action(struct rte_eth_dev *dev)
        /* Check if default flow is registered. */
        if (!priv->mreg_cp_tbl)
                return;
-       mcp_res = (void *)mlx5_hlist_lookup(priv->mreg_cp_tbl, 0ULL);
+       mcp_res = (void *)mlx5_hlist_lookup(priv->mreg_cp_tbl,
+                                           MLX5_DEFAULT_COPY_ID);
        if (!mcp_res)
                return;
        assert(mcp_res->flow);
@@ -3166,7 +3171,7 @@ flow_mreg_add_default_copy_action(struct rte_eth_dev *dev,
            !mlx5_flow_ext_mreg_supported(dev) ||
            !priv->sh->dv_regc0_mask)
                return 0;
-       mcp_res = flow_mreg_add_copy_action(dev, 0, error);
+       mcp_res = flow_mreg_add_copy_action(dev, MLX5_DEFAULT_COPY_ID, error);
        if (!mcp_res)
                return -rte_errno;
        return 0;
@@ -3538,7 +3543,7 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
         * Get the id from the qrss_pool to make qrss share the id with meter.
         */
        tag_id = flow_qrss_get_id(dev);
-       set_tag->data = rte_cpu_to_be_32(tag_id);
+       set_tag->data = tag_id << MLX5_MTR_COLOR_BITS;
        tag_action->conf = set_tag;
        return tag_id;
 }
@@ -3976,13 +3981,14 @@ flow_create_split_meter(struct rte_eth_dev *dev,
                actions_n = flow_check_meter_action(actions, &mtr);
        if (mtr) {
                struct mlx5_rte_flow_item_tag *tag_spec;
+               struct mlx5_rte_flow_item_tag *tag_mask;
                /* The five prefix actions: meter, decap, encap, tag, end. */
                act_size = sizeof(struct rte_flow_action) * (actions_n + 5) +
                           sizeof(struct rte_flow_action_set_tag);
                /* tag, end. */
 #define METER_SUFFIX_ITEM 3
                item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +
-                           sizeof(struct mlx5_rte_flow_item_tag);
+                           sizeof(struct mlx5_rte_flow_item_tag) * 2;
                sfx_actions = rte_zmalloc(__func__, (act_size + item_size), 0);
                if (!sfx_actions)
                        return rte_flow_error_set(error, ENOMEM,
@@ -4009,13 +4015,15 @@ flow_create_split_meter(struct rte_eth_dev *dev,
                             act_size);
                tag_spec = (struct mlx5_rte_flow_item_tag *)(sfx_items +
                            METER_SUFFIX_ITEM);
-               tag_spec->data = rte_cpu_to_be_32(dev_flow->mtr_flow_id);
+               tag_spec->data = dev_flow->mtr_flow_id << MLX5_MTR_COLOR_BITS;
                tag_spec->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0,
                                                    error);
+               tag_mask = tag_spec + 1;
+               tag_mask->data = 0xffffff00;
                sfx_items->type = MLX5_RTE_FLOW_ITEM_TYPE_TAG;
                sfx_items->spec = tag_spec;
                sfx_items->last = NULL;
-               sfx_items->mask = NULL;
+               sfx_items->mask = tag_mask;
                sfx_items++;
                sfx_port_id_item = find_port_id_item(items);
                if (sfx_port_id_item) {
@@ -4024,7 +4032,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
                        sfx_items++;
                }
                sfx_items->type = RTE_FLOW_ITEM_TYPE_END;
-               sfx_items -= METER_SUFFIX_ITEM;
+               sfx_items -= sfx_port_id_item ? 2 : 1;
                /* Setting the sfx group atrr. */
                sfx_attr.group = sfx_attr.transfer ?
                                (MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
@@ -5666,3 +5674,28 @@ mlx5_flow_discover_mreg_c(struct rte_eth_dev *dev)
                config->flow_mreg_c[n] = REG_NONE;
        return 0;
 }
+
+/**
+ * Dump flow raw hw data to file
+ *
+ * @param[in] dev
+ *    The pointer to Ethernet device.
+ * @param[in] file
+ *   A pointer to a file for output.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. PMDs initialize this
+ *   structure in case of error only.
+ * @return
+ *   0 on success, a nagative value otherwise.
+ */
+int
+mlx5_flow_dev_dump(struct rte_eth_dev *dev,
+                  FILE *file,
+                  struct rte_flow_error *error __rte_unused)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_ibv_shared *sh = priv->sh;
+
+       return mlx5_devx_cmd_flow_dump(sh->fdb_domain, sh->rx_domain,
+                                      sh->tx_domain, file);
+}