get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/91529/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 91529,
    "url": "https://patches.dpdk.org/api/patches/91529/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210415050929.2082949-5-lizh@nvidia.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210415050929.2082949-5-lizh@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210415050929.2082949-5-lizh@nvidia.com",
    "date": "2021-04-15T05:09:29",
    "name": "[v6,4/4] net/mlx5: connect meter policy to created flows",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "8d78711bc83d626b52cc9c36f642eddf233d9267",
    "submitter": {
        "id": 1967,
        "url": "https://patches.dpdk.org/api/people/1967/?format=api",
        "name": "Li Zhang",
        "email": "lizh@nvidia.com"
    },
    "delegate": {
        "id": 3268,
        "url": "https://patches.dpdk.org/api/users/3268/?format=api",
        "username": "rasland",
        "first_name": "Raslan",
        "last_name": "Darawsheh",
        "email": "rasland@nvidia.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20210415050929.2082949-5-lizh@nvidia.com/mbox/",
    "series": [
        {
            "id": 16391,
            "url": "https://patches.dpdk.org/api/series/16391/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=16391",
            "date": "2021-04-15T05:09:25",
            "name": "net/mlx5: support meter policy operations",
            "version": 6,
            "mbox": "https://patches.dpdk.org/series/16391/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/91529/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/91529/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id BF396A0A0C;\n\tThu, 15 Apr 2021 07:09:41 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id A4871161FA9;\n\tThu, 15 Apr 2021 07:09:41 +0200 (CEST)",
            "from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n by mails.dpdk.org (Postfix) with ESMTP id 69761161FA4\n for <dev@dpdk.org>; Thu, 15 Apr 2021 07:09:40 +0200 (CEST)",
            "from Internal Mail-Server by MTLPINE1 (envelope-from\n lizh@nvidia.com)\n with SMTP; 15 Apr 2021 08:09:35 +0300",
            "from nvidia.com (c-235-17-1-009.mtl.labs.mlnx [10.235.17.9])\n by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 13F59YFe027304;\n Thu, 15 Apr 2021 08:09:35 +0300"
        ],
        "From": "Li Zhang <lizh@nvidia.com>",
        "To": "dekelp@nvidia.com, orika@nvidia.com, viacheslavo@nvidia.com,\n matan@nvidia.com, shahafs@nvidia.com",
        "Cc": "dev@dpdk.org, thomas@monjalon.net, rasland@nvidia.com, roniba@nvidia.com,\n Shun Hao <shunh@nvidia.com>",
        "Date": "Thu, 15 Apr 2021 08:09:29 +0300",
        "Message-Id": "<20210415050929.2082949-5-lizh@nvidia.com>",
        "X-Mailer": "git-send-email 2.21.0",
        "In-Reply-To": "<20210415050929.2082949-1-lizh@nvidia.com>",
        "References": "<20210401081624.1482490-1-lizh@nvidia.com>\n <20210415050929.2082949-1-lizh@nvidia.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v6 4/4] net/mlx5: connect meter policy to created\n flows",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Shun Hao <shunh@nvidia.com>\n\nCurrently ASO meter must be followed by policy table, so this adds\nthe support that connecting meter and policy table.\n\nThere are several cases to be considered:\n1. For non-termination policy, connect meter to the default policy\ntable.\n2. For non-RSS termination policy case, simply get the policy\ntable id and connect meter to it.\n3. For RSS termination policy case, need to split the flow due\nto RSS info in policy, and translate each sub-flow using that RSS,\nthen create the sub policy table to be connected.\n4. In termination policy case, if there's no actions to modify the\npacket before meter, no need to use set_tag to save meter id in\nregister. Only add a new flow in drop table using the same match\ncriteria as suf-flow, to save cache miss.\n\nSigned-off-by: Shun Hao <shunh@nvidia.com>\nAcked-by: Matan Azrad <matan@nvidia.com>\n---\n doc/guides/nics/mlx5.rst        |  12 +\n drivers/net/mlx5/mlx5_flow.c    | 446 ++++++++++++++++++++++++++++----\n drivers/net/mlx5/mlx5_flow.h    |   4 +\n drivers/net/mlx5/mlx5_flow_dv.c |  15 ++\n 4 files changed, 420 insertions(+), 57 deletions(-)",
    "diff": "diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst\nindex d287b3aca1..1e67a91ee7 100644\n--- a/doc/guides/nics/mlx5.rst\n+++ b/doc/guides/nics/mlx5.rst\n@@ -106,6 +106,7 @@ Features\n - E-Switch mirroring and modify.\n - 21844 flow priorities for ingress or egress flow groups greater than 0 and for any transfer\n   flow group.\n+- Flow metering, including meter policy API.\n \n Limitations\n -----------\n@@ -400,10 +401,21 @@ Limitations\n   - Hairpin in switchdev SR-IOV mode is not supported till now.\n \n - Meter:\n+\n   - All the meter colors with drop action will be counted only by the global drop statistics.\n   - Green color is not supported with drop action.\n   - Yellow detection is not supported.\n   - Red color must be with drop action.\n+  - Meter statistics are supported only for drop case.\n+  - Meter yellow color detection is not supported.\n+  - A meter action created with pre-defined policy must be the last action in the flow except single case where the policy actions are:\n+     - green: NULL or END.\n+     - yellow: NULL or END.\n+     - RED: DROP / END.\n+  - The only supported meter policy actions:\n+     - green: QUEUE, RSS, PORT_ID, JUMP, MARK and SET_TAG.\n+     - yellow: must be empty.\n+     - RED: must be DROP.\n \n Statistics\n ----------\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex 77590bbbed..71fce4a524 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -3343,18 +3343,52 @@ flow_drv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)\n \tfops->destroy(dev, flow);\n }\n \n+/**\n+ * Flow driver find RSS policy tbl API. This abstracts calling driver\n+ * specific functions. Parent flow (rte_flow) should have driver\n+ * type (drv_type). It will find the RSS policy table that has the rss_desc.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in, out] flow\n+ *   Pointer to flow structure.\n+ * @param[in] policy_id\n+ *   The policy id of a meter.\n+ * @param[in] rss_desc\n+ *   Pointer to rss_desc\n+ */\n+static struct mlx5_flow_meter_sub_policy *\n+flow_drv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,\n+\t\tstruct rte_flow *flow,\n+\t\tstruct mlx5_flow_meter_policy *policy,\n+\t\tstruct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])\n+{\n+\tconst struct mlx5_flow_driver_ops *fops;\n+\tenum mlx5_flow_drv_type type = flow->drv_type;\n+\n+\tMLX5_ASSERT(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);\n+\tfops = flow_get_drv_ops(type);\n+\treturn fops->meter_sub_policy_rss_prepare(dev, policy, rss_desc);\n+}\n+\n /**\n  * Get RSS action from the action list.\n  *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n  * @param[in] actions\n  *   Pointer to the list of actions.\n+ * @param[in] flow\n+ *   Parent flow structure pointer.\n  *\n  * @return\n  *   Pointer to the RSS action if exist, else return NULL.\n  */\n static const struct rte_flow_action_rss*\n-flow_get_rss_action(const struct rte_flow_action actions[])\n+flow_get_rss_action(struct rte_eth_dev *dev,\n+\t\t    const struct rte_flow_action actions[])\n {\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n \tconst struct rte_flow_action_rss *rss = NULL;\n \n \tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {\n@@ -3372,6 +3406,23 @@ flow_get_rss_action(const struct rte_flow_action actions[])\n \t\t\t\t\trss = act->conf;\n \t\t\tbreak;\n \t\t}\n+\t\tcase RTE_FLOW_ACTION_TYPE_METER:\n+\t\t{\n+\t\t\tuint32_t mtr_idx;\n+\t\t\tstruct mlx5_flow_meter_info *fm;\n+\t\t\tstruct mlx5_flow_meter_policy *policy;\n+\t\t\tconst struct rte_flow_action_meter *mtr = actions->conf;\n+\n+\t\t\tfm = mlx5_flow_meter_find(priv, mtr->mtr_id, &mtr_idx);\n+\t\t\tif (fm) {\n+\t\t\t\tpolicy = mlx5_flow_meter_policy_find(dev,\n+\t\t\t\t\t\tfm->policy_id, NULL);\n+\t\t\t\tif (policy && policy->is_rss)\n+\t\t\t\t\trss =\n+\t\t\t\tpolicy->act_cnt[RTE_COLOR_GREEN].rss->conf;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n@@ -3670,13 +3721,75 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],\n \treturn actions_n + 1;\n }\n \n+/**\n+ * Check if the action will change packet.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] type\n+ *   action type.\n+ *\n+ * @return\n+ *   true if action will change packet, false otherwise.\n+ */\n+static bool flow_check_modify_action_type(struct rte_eth_dev *dev,\n+\t\t\t\t\t  enum rte_flow_action_type type)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\n+\tswitch (type) {\n+\tcase RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_MAC_DST:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_TP_SRC:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_TP_DST:\n+\tcase RTE_FLOW_ACTION_TYPE_DEC_TTL:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_TTL:\n+\tcase RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:\n+\tcase RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:\n+\tcase RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:\n+\tcase RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_META:\n+\tcase RTE_FLOW_ACTION_TYPE_SET_TAG:\n+\tcase RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:\n+\tcase RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:\n+\tcase RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:\n+\tcase RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:\n+\tcase RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:\n+\tcase RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:\n+\tcase RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:\n+\tcase RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:\n+\tcase RTE_FLOW_ACTION_TYPE_RAW_ENCAP:\n+\tcase RTE_FLOW_ACTION_TYPE_RAW_DECAP:\n+\tcase RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:\n+\t\treturn true;\n+\tcase RTE_FLOW_ACTION_TYPE_FLAG:\n+\tcase RTE_FLOW_ACTION_TYPE_MARK:\n+\t\tif (priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)\n+\t\t\treturn true;\n+\t\telse\n+\t\t\treturn false;\n+\tdefault:\n+\t\treturn false;\n+\t}\n+}\n+\n /**\n  * Check meter action from the action list.\n  *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n  * @param[in] actions\n  *   Pointer to the list of actions.\n  * @param[out] has_mtr\n  *   Pointer to the meter exist flag.\n+ * @param[out] has_modify\n+ *   Pointer to the flag showing there's packet change action.\n  * @param[out] meter_id\n  *   Pointer to the meter id.\n  *\n@@ -3684,9 +3797,9 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],\n  *   Total number of actions.\n  */\n static int\n-flow_check_meter_action(const struct rte_flow_action actions[],\n-\t\t\tbool *has_mtr,\n-\t\t\tuint32_t *meter_id)\n+flow_check_meter_action(struct rte_eth_dev *dev,\n+\t\t\tconst struct rte_flow_action actions[],\n+\t\t\tbool *has_mtr, bool *has_modify, uint32_t *meter_id)\n {\n \tconst struct rte_flow_action_meter *mtr = NULL;\n \tint actions_n = 0;\n@@ -3703,6 +3816,9 @@ flow_check_meter_action(const struct rte_flow_action actions[],\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n+\t\tif (!*has_mtr)\n+\t\t\t*has_modify |= flow_check_modify_action_type(dev,\n+\t\t\t\t\t\t\t\tactions->type);\n \t\tactions_n++;\n \t}\n \t/* Count RTE_FLOW_ACTION_TYPE_END. */\n@@ -4348,6 +4464,108 @@ flow_create_split_inner(struct rte_eth_dev *dev,\n \treturn flow_drv_translate(dev, dev_flow, attr, items, actions, error);\n }\n \n+/**\n+ * Get the sub policy of a meter.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] flow\n+ *   Parent flow structure pointer.\n+ * @param[in] policy_id;\n+ *   Meter Policy id.\n+ * @param[in] attr\n+ *   Flow rule attributes.\n+ * @param[in] items\n+ *   Pattern specification (list terminated by the END pattern item).\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ *\n+ * @return\n+ *   Pointer to the meter sub policy, NULL otherwise and rte_errno is set.\n+ */\n+static struct mlx5_flow_meter_sub_policy *\n+get_meter_sub_policy(struct rte_eth_dev *dev,\n+\t\t     struct rte_flow *flow,\n+\t\t     uint32_t policy_id,\n+\t\t     const struct rte_flow_attr *attr,\n+\t\t     const struct rte_flow_item items[],\n+\t\t     struct rte_flow_error *error)\n+{\n+\tstruct mlx5_flow_meter_policy *policy;\n+\tstruct mlx5_flow_meter_sub_policy *sub_policy = NULL;\n+\n+\tpolicy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);\n+\tif (!policy) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"Failed to find Meter Policy.\");\n+\t\tgoto exit;\n+\t}\n+\tif (policy->is_rss) {\n+\t\tstruct mlx5_flow_workspace *wks =\n+\t\t\t\tmlx5_flow_get_thread_workspace();\n+\t\tstruct mlx5_flow_rss_desc rss_desc_v[MLX5_MTR_RTE_COLORS];\n+\t\tstruct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS] = {0};\n+\t\tuint32_t i;\n+\n+\t\tMLX5_ASSERT(wks);\n+\t\t/**\n+\t\t * This is a tmp dev_flow,\n+\t\t * no need to register any matcher for it in translate.\n+\t\t */\n+\t\twks->skip_matcher_reg = 1;\n+\t\tfor (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {\n+\t\t\tstruct mlx5_flow dev_flow = {0};\n+\t\t\tstruct mlx5_flow_handle dev_handle = { {0} };\n+\t\t\tconst void *rss_act = policy->act_cnt[i].rss->conf;\n+\t\t\tstruct rte_flow_action rss_actions[2] = {\n+\t\t\t\t[0] = {\n+\t\t\t\t\t.type = RTE_FLOW_ACTION_TYPE_RSS,\n+\t\t\t\t\t.conf = rss_act\n+\t\t\t\t},\n+\t\t\t\t[1] = {\n+\t\t\t\t\t.type = RTE_FLOW_ACTION_TYPE_END,\n+\t\t\t\t\t.conf = NULL\n+\t\t\t\t}\n+\t\t\t};\n+\n+\t\t\tdev_flow.handle = &dev_handle;\n+\t\t\tdev_flow.ingress = attr->ingress;\n+\t\t\tdev_flow.flow = flow;\n+\t\t\tdev_flow.external = 0;\n+#ifdef HAVE_IBV_FLOW_DV_SUPPORT\n+\t\t\tdev_flow.dv.transfer = attr->transfer;\n+#endif\n+\t\t\t/* Translate RSS action to get rss hash fields. */\n+\t\t\tif (flow_drv_translate(dev, &dev_flow, attr,\n+\t\t\t\t\t\titems, rss_actions, error))\n+\t\t\t\tgoto exit;\n+\t\t\trss_desc_v[i] = wks->rss_desc;\n+\t\t\trss_desc_v[i].key_len = MLX5_RSS_HASH_KEY_LEN;\n+\t\t\trss_desc_v[i].hash_fields = dev_flow.hash_fields;\n+\t\t\trss_desc_v[i].queue_num = rss_desc_v[i].hash_fields ?\n+\t\t\t\t\t\t  rss_desc_v[i].queue_num : 1;\n+\t\t\trss_desc[i] = &rss_desc_v[i];\n+\t\t}\n+\t\tsub_policy = flow_drv_meter_sub_policy_rss_prepare(dev,\n+\t\t\t\t\t\tflow, policy, rss_desc);\n+\t} else {\n+\t\tenum mlx5_meter_domain mtr_domain =\n+\t\t\tattr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :\n+\t\t\t\tattr->egress ? MLX5_MTR_DOMAIN_EGRESS :\n+\t\t\t\t\tMLX5_MTR_DOMAIN_INGRESS;\n+\t\tsub_policy = policy->sub_policys[mtr_domain][0];\n+\t}\n+\tif (!sub_policy) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\"Failed to get meter sub-policy.\");\n+\t\tgoto exit;\n+\t}\n+exit:\n+\treturn sub_policy;\n+}\n+\n /**\n  * Split the meter flow.\n  *\n@@ -4378,13 +4596,15 @@ flow_create_split_inner(struct rte_eth_dev *dev,\n  *   Suffix flow actions.\n  * @param[out] actions_pre\n  *   Prefix flow actions.\n+ * @param[out] mtr_flow_id\n+ *   Pointer to meter flow id.\n  * @param[out] error\n  *   Perform verbose error reporting if not NULL.\n  *\n  * @return\n- *   The flow id, 0 otherwise and rte_errno is set.\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static uint32_t\n+static int\n flow_meter_split_prep(struct rte_eth_dev *dev,\n \t\t      struct rte_flow *flow,\n \t\t      struct mlx5_flow_meter_info *fm,\n@@ -4394,6 +4614,7 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \t\t      const struct rte_flow_action actions[],\n \t\t      struct rte_flow_action actions_sfx[],\n \t\t      struct rte_flow_action actions_pre[],\n+\t\t      uint32_t *mtr_flow_id,\n \t\t      struct rte_flow_error *error)\n {\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n@@ -4407,7 +4628,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \tuint32_t tag_id = 0;\n \tbool copy_vlan = false;\n \tstruct rte_flow_action *hw_mtr_action;\n-\tstruct rte_flow_action_jump *jump_data;\n \tstruct rte_flow_action *action_pre_head = NULL;\n \tbool mtr_first = priv->sh->meter_aso_en &&\n \t\t\t(attr->egress ||\n@@ -4462,7 +4682,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \t\t\tbreak;\n \t\t}\n \t\tif (!action_cur)\n-\t\t\taction_cur = actions_sfx++;\n+\t\t\taction_cur = (fm->def_policy) ?\n+\t\t\t\t\tactions_sfx++ : actions_pre++;\n \t\tmemcpy(action_cur, actions, sizeof(struct rte_flow_action));\n \t}\n \t/* Add end action to the actions. */\n@@ -4472,38 +4693,61 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \t\t * For ASO meter, need to add an extra jump action explicitly,\n \t\t * to jump from meter to policer table.\n \t\t */\n-\t\thw_mtr_action = actions_pre;\n-\t\thw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP;\n-\t\tactions_pre++;\n-\t\tactions_pre->type = RTE_FLOW_ACTION_TYPE_END;\n-\t\tactions_pre++;\n-\t\tjump_data = (struct rte_flow_action_jump *)actions_pre;\n-\t\tjump_data->group = attr->transfer ?\n-\t\t\t\t(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :\n-\t\t\t\t MLX5_FLOW_TABLE_LEVEL_POLICY;\n-\t\thw_mtr_action->conf = jump_data;\n-\t\tactions_pre = (struct rte_flow_action *)(jump_data + 1);\n-\t} else {\n-\t\tactions_pre->type = RTE_FLOW_ACTION_TYPE_END;\n-\t\tactions_pre++;\n+\t\tstruct mlx5_flow_meter_sub_policy *sub_policy;\n+\t\tstruct mlx5_flow_tbl_data_entry *tbl_data;\n+\n+\t\tif (!fm->def_policy) {\n+\t\t\tsub_policy = get_meter_sub_policy(dev, flow,\n+\t\t\t\t\t\t\t  fm->policy_id, attr,\n+\t\t\t\t\t\t\t  items, error);\n+\t\t\tif (!sub_policy)\n+\t\t\t\treturn -rte_errno;\n+\t\t} else {\n+\t\t\tenum mlx5_meter_domain mtr_domain =\n+\t\t\tattr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :\n+\t\t\t\tattr->egress ? MLX5_MTR_DOMAIN_EGRESS :\n+\t\t\t\t\tMLX5_MTR_DOMAIN_INGRESS;\n+\n+\t\t\tsub_policy =\n+\t\t\t&priv->sh->mtrmng->def_policy[mtr_domain]->sub_policy;\n+\t\t}\n+\t\ttbl_data = container_of(sub_policy->tbl_rsc,\n+\t\t\t\t\tstruct mlx5_flow_tbl_data_entry, tbl);\n+\t\thw_mtr_action = actions_pre++;\n+\t\thw_mtr_action->type = (enum rte_flow_action_type)\n+\t\t\t\t      MLX5_RTE_FLOW_ACTION_TYPE_JUMP;\n+\t\thw_mtr_action->conf = tbl_data->jump.action;\n \t}\n-\t/* Generate meter flow_id only if support multiple flows per meter. */\n-\tmlx5_ipool_malloc(fm->flow_ipool, &tag_id);\n-\tif (!tag_id)\n+\tactions_pre->type = RTE_FLOW_ACTION_TYPE_END;\n+\tactions_pre++;\n+\tif (!tag_action)\n \t\treturn rte_flow_error_set(error, ENOMEM,\n-\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n-\t\t\t\t\"Failed to allocate meter flow id.\");\n-\tflow_id = tag_id - 1;\n-\tflow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);\n-\tflow_id_bits = flow_id_bits ? flow_id_bits : 1;\n-\tif ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {\n-\t\tmlx5_ipool_free(fm->flow_ipool, tag_id);\n-\t\treturn rte_flow_error_set(error, EINVAL,\n-\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n-\t\t\t\t\"Meter flow id exceeds max limit.\");\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t\t\"No tag action space.\");\n+\tif (!mtr_flow_id) {\n+\t\ttag_action->type = RTE_FLOW_ACTION_TYPE_VOID;\n+\t\tgoto exit;\n+\t}\n+\t/* Only default-policy Meter creates mtr flow id. */\n+\tif (fm->def_policy) {\n+\t\tmlx5_ipool_malloc(fm->flow_ipool, &tag_id);\n+\t\tif (!tag_id)\n+\t\t\treturn rte_flow_error_set(error, ENOMEM,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t\t\"Failed to allocate meter flow id.\");\n+\t\tflow_id = tag_id - 1;\n+\t\tflow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);\n+\t\tflow_id_bits = flow_id_bits ? flow_id_bits : 1;\n+\t\tif ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) >\n+\t\t    mtr_reg_bits) {\n+\t\t\tmlx5_ipool_free(fm->flow_ipool, tag_id);\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t\t\"Meter flow id exceeds max limit.\");\n+\t\t}\n+\t\tif (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)\n+\t\t\tpriv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;\n \t}\n-\tif (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)\n-\t\tpriv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;\n \t/* Prepare the suffix subflow items. */\n \ttag_item = sfx_items++;\n \tfor (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {\n@@ -4533,7 +4777,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \tsfx_items->type = RTE_FLOW_ITEM_TYPE_END;\n \tsfx_items++;\n \t/* Build tag actions and items for meter_id/meter flow_id. */\n-\tassert(tag_action);\n \tset_tag = (struct mlx5_rte_flow_action_set_tag *)actions_pre;\n \ttag_item_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;\n \ttag_item_mask = tag_item_spec + 1;\n@@ -4551,8 +4794,9 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \t */\n \tfor (shift = 0; shift < flow_id_bits; shift++)\n \t\tflow_id_reversed = (flow_id_reversed << 1) |\n-\t\t\t      ((flow_id >> shift) & 0x1);\n-\tset_tag->data |= flow_id_reversed << (mtr_reg_bits - flow_id_bits);\n+\t\t\t\t((flow_id >> shift) & 0x1);\n+\tset_tag->data |=\n+\t\tflow_id_reversed << (mtr_reg_bits - flow_id_bits);\n \ttag_item_spec->id = set_tag->id;\n \ttag_item_spec->data = set_tag->data << mtr_id_offset;\n \ttag_item_mask->data = UINT32_MAX << mtr_id_offset;\n@@ -4564,7 +4808,10 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \ttag_item->spec = tag_item_spec;\n \ttag_item->last = NULL;\n \ttag_item->mask = tag_item_mask;\n-\treturn tag_id;\n+exit:\n+\tif (mtr_flow_id)\n+\t\t*mtr_flow_id = tag_id;\n+\treturn 0;\n }\n \n /**\n@@ -5228,6 +5475,57 @@ flow_create_split_metadata(struct rte_eth_dev *dev,\n \treturn ret;\n }\n \n+/**\n+ * Create meter internal drop flow with the original pattern.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] flow\n+ *   Parent flow structure pointer.\n+ * @param[in] attr\n+ *   Flow rule attributes.\n+ * @param[in] items\n+ *   Pattern specification (list terminated by the END pattern item).\n+ * @param[in] flow_split_info\n+ *   Pointer to flow split info structure.\n+ * @param[in] fm\n+ *   Pointer to flow meter structure.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ * @return\n+ *   0 on success, negative value otherwise\n+ */\n+static uint32_t\n+flow_meter_create_drop_flow_with_org_pattern(struct rte_eth_dev *dev,\n+\t\t\tstruct rte_flow *flow,\n+\t\t\tconst struct rte_flow_attr *attr,\n+\t\t\tconst struct rte_flow_item items[],\n+\t\t\tstruct mlx5_flow_split_info *flow_split_info,\n+\t\t\tstruct mlx5_flow_meter_info *fm,\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tstruct mlx5_flow *dev_flow = NULL;\n+\tstruct rte_flow_attr drop_attr = *attr;\n+\tstruct rte_flow_action drop_actions[3];\n+\tstruct mlx5_flow_split_info drop_split_info = *flow_split_info;\n+\n+\tMLX5_ASSERT(fm->drop_cnt);\n+\tdrop_actions[0].type =\n+\t\t(enum rte_flow_action_type)MLX5_RTE_FLOW_ACTION_TYPE_COUNT;\n+\tdrop_actions[0].conf = (void *)(uintptr_t)fm->drop_cnt;\n+\tdrop_actions[1].type = RTE_FLOW_ACTION_TYPE_DROP;\n+\tdrop_actions[1].conf = NULL;\n+\tdrop_actions[2].type = RTE_FLOW_ACTION_TYPE_END;\n+\tdrop_actions[2].conf = NULL;\n+\tdrop_split_info.external = false;\n+\tdrop_split_info.skip_scale |= 1 << MLX5_SCALE_FLOW_GROUP_BIT;\n+\tdrop_split_info.table_id = MLX5_MTR_TABLE_ID_DROP;\n+\tdrop_attr.group = MLX5_FLOW_TABLE_LEVEL_METER;\n+\treturn flow_create_split_inner(dev, flow, &dev_flow,\n+\t\t\t\t&drop_attr, items, drop_actions,\n+\t\t\t\t&drop_split_info, error);\n+}\n+\n /**\n  * The splitting for meter feature.\n  *\n@@ -5272,18 +5570,21 @@ flow_create_split_meter(struct rte_eth_dev *dev,\n \tstruct mlx5_flow *dev_flow = NULL;\n \tstruct rte_flow_attr sfx_attr = *attr;\n \tstruct mlx5_flow_meter_info *fm = NULL;\n+\tuint8_t skip_scale_restore;\n \tbool has_mtr = false;\n-\tuint32_t meter_id;\n+\tbool has_modify = false;\n+\tbool set_mtr_reg = true;\n+\tuint32_t meter_id = 0;\n \tuint32_t mtr_idx = 0;\n-\tuint32_t mtr_tag_id = 0;\n+\tuint32_t mtr_flow_id = 0;\n \tsize_t act_size;\n \tsize_t item_size;\n \tint actions_n = 0;\n \tint ret = 0;\n \n \tif (priv->mtr_en)\n-\t\tactions_n = flow_check_meter_action(actions, &has_mtr,\n-\t\t\t\t\t\t    &meter_id);\n+\t\tactions_n = flow_check_meter_action(dev, actions, &has_mtr,\n+\t\t\t\t\t\t    &has_modify, &meter_id);\n \tif (has_mtr) {\n \t\tif (flow->meter) {\n \t\t\tfm = flow_dv_meter_find_by_idx(priv, flow->meter);\n@@ -5303,11 +5604,20 @@ flow_create_split_meter(struct rte_eth_dev *dev,\n \t\t\t\treturn -rte_errno;\n \t\t\tflow->meter = mtr_idx;\n \t\t}\n+\t\tMLX5_ASSERT(wks);\n \t\twks->fm = fm;\n+\t\t/*\n+\t\t * If it isn't default-policy Meter, and\n+\t\t * 1. There's no action in flow to change\n+\t\t *    packet (modify/encap/decap etc.), OR\n+\t\t * 2. No drop count needed for this meter.\n+\t\t * no need to use regC to save meter id anymore.\n+\t\t */\n+\t\tif (!fm->def_policy && (!has_modify || !fm->drop_cnt))\n+\t\t\tset_mtr_reg = false;\n \t\t/* Prefix actions: meter, decap, encap, tag, jump, end. */\n \t\tact_size = sizeof(struct rte_flow_action) * (actions_n + 6) +\n-\t\t\t   sizeof(struct mlx5_rte_flow_action_set_tag) +\n-\t\t\t   sizeof(struct rte_flow_action_jump);\n+\t\t\t   sizeof(struct mlx5_rte_flow_action_set_tag);\n \t\t/* Suffix items: tag, vlan, port id, end. */\n #define METER_SUFFIX_ITEM 4\n \t\titem_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +\n@@ -5321,27 +5631,48 @@ flow_create_split_meter(struct rte_eth_dev *dev,\n \t\t\t\t\t\t  \"meter flow\");\n \t\tsfx_items = (struct rte_flow_item *)((char *)sfx_actions +\n \t\t\t     act_size);\n-\t\tpre_actions = sfx_actions + actions_n;\n-\t\tmtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr,\n-\t\t\t\t\t\t   items, sfx_items, actions,\n-\t\t\t\t\t\t   sfx_actions, pre_actions,\n-\t\t\t\t\t\t   error);\n-\t\tif (!mtr_tag_id) {\n+\t\t/* There's no suffix flow for meter of non-default policy. */\n+\t\tif (!fm->def_policy)\n+\t\t\tpre_actions = sfx_actions + 1;\n+\t\telse\n+\t\t\tpre_actions = sfx_actions + actions_n;\n+\t\tret = flow_meter_split_prep(dev, flow, fm, &sfx_attr,\n+\t\t\t\t\t    items, sfx_items, actions,\n+\t\t\t\t\t    sfx_actions, pre_actions,\n+\t\t\t\t\t    (set_mtr_reg ? &mtr_flow_id : NULL),\n+\t\t\t\t\t    error);\n+\t\tif (ret) {\n \t\t\tret = -rte_errno;\n \t\t\tgoto exit;\n \t\t}\n \t\t/* Add the prefix subflow. */\n \t\tflow_split_info->prefix_mark = 0;\n+\t\tskip_scale_restore = flow_split_info->skip_scale;\n+\t\tflow_split_info->skip_scale |=\n+\t\t\t1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT;\n \t\tret = flow_create_split_inner(dev, flow, &dev_flow,\n \t\t\t\t\t      attr, items, pre_actions,\n \t\t\t\t\t      flow_split_info, error);\n+\t\tflow_split_info->skip_scale = skip_scale_restore;\n \t\tif (ret) {\n-\t\t\tmlx5_ipool_free(fm->flow_ipool, mtr_tag_id);\n+\t\t\tif (mtr_flow_id)\n+\t\t\t\tmlx5_ipool_free(fm->flow_ipool, mtr_flow_id);\n \t\t\tret = -rte_errno;\n \t\t\tgoto exit;\n \t\t}\n-\t\tdev_flow->handle->split_flow_id = mtr_tag_id;\n-\t\tdev_flow->handle->is_meter_flow_id = 1;\n+\t\tif (mtr_flow_id) {\n+\t\t\tdev_flow->handle->split_flow_id = mtr_flow_id;\n+\t\t\tdev_flow->handle->is_meter_flow_id = 1;\n+\t\t}\n+\t\tif (!fm->def_policy) {\n+\t\t\tif (!set_mtr_reg && fm->drop_cnt)\n+\t\t\t\tret =\n+\t\t\tflow_meter_create_drop_flow_with_org_pattern(dev, flow,\n+\t\t\t\t\t\t\t&sfx_attr, items,\n+\t\t\t\t\t\t\tflow_split_info,\n+\t\t\t\t\t\t\tfm, error);\n+\t\t\tgoto exit;\n+\t\t}\n \t\t/* Setting the sfx group atrr. */\n \t\tsfx_attr.group = sfx_attr.transfer ?\n \t\t\t\t(MLX5_FLOW_TABLE_LEVEL_METER - 1) :\n@@ -5349,6 +5680,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,\n \t\tflow_split_info->prefix_layers =\n \t\t\t\tflow_get_prefix_layer_flags(dev_flow);\n \t\tflow_split_info->prefix_mark = dev_flow->handle->mark;\n+\t\tflow_split_info->table_id = MLX5_MTR_TABLE_ID_SUFFIX;\n \t}\n \t/* Add the prefix subflow. */\n \tret = flow_create_split_metadata(dev, flow,\n@@ -5736,7 +6068,7 @@ flow_list_create(struct rte_eth_dev *dev, uint32_t *list,\n \tmemset(rss_desc, 0, offsetof(struct mlx5_flow_rss_desc, queue));\n \t/* RSS Action only works on NIC RX domain */\n \tif (attr->ingress && !attr->transfer)\n-\t\trss = flow_get_rss_action(p_actions_rx);\n+\t\trss = flow_get_rss_action(dev, p_actions_rx);\n \tif (rss) {\n \t\tif (flow_rss_workspace_adjust(wks, rss_desc, rss->queue_num))\n \t\t\treturn 0;\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nindex cc9b37b9eb..8a0a84a604 100644\n--- a/drivers/net/mlx5/mlx5_flow.h\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -37,6 +37,8 @@ enum mlx5_rte_flow_action_type {\n \tMLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS,\n \tMLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET,\n \tMLX5_RTE_FLOW_ACTION_TYPE_AGE,\n+\tMLX5_RTE_FLOW_ACTION_TYPE_JUMP,\n+\tMLX5_RTE_FLOW_ACTION_TYPE_COUNT,\n };\n \n #define MLX5_SHARED_ACTION_TYPE_OFFSET 30\n@@ -1048,6 +1050,8 @@ struct mlx5_flow_workspace {\n \tuint32_t rssq_num; /* Allocated queue num in rss_desc. */\n \tuint32_t flow_idx; /* Intermediate device flow index. */\n \tstruct mlx5_flow_meter_info *fm; /* Pointer to the meter in flow. */\n+\tuint32_t skip_matcher_reg:1;\n+\t/* Indicates if need to skip matcher register in translate. */\n };\n \n struct mlx5_flow_split_info {\ndiff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c\nindex ed17bd903f..eedbe2e43b 100644\n--- a/drivers/net/mlx5/mlx5_flow_dv.c\n+++ b/drivers/net/mlx5/mlx5_flow_dv.c\n@@ -7423,6 +7423,7 @@ flow_dv_prepare(struct rte_eth_dev *dev,\n \tstruct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();\n \n \tMLX5_ASSERT(wks);\n+\twks->skip_matcher_reg = 0;\n \t/* In case of corrupting the memory. */\n \tif (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {\n \t\trte_flow_error_set(error, ENOSPC,\n@@ -11254,6 +11255,7 @@ flow_dv_translate(struct rte_eth_dev *dev,\n \t\tint action_type = actions->type;\n \t\tconst struct rte_flow_action *found_action = NULL;\n \t\tuint32_t jump_group = 0;\n+\t\tstruct mlx5_flow_counter *cnt;\n \n \t\tif (!mlx5_flow_os_action_supported(action_type))\n \t\t\treturn rte_flow_error_set(error, ENOTSUP,\n@@ -11434,6 +11436,12 @@ flow_dv_translate(struct rte_eth_dev *dev,\n \t\t\t\tage = action->conf;\n \t\t\taction_flags |= MLX5_FLOW_ACTION_COUNT;\n \t\t\tbreak;\n+\t\tcase MLX5_RTE_FLOW_ACTION_TYPE_COUNT:\n+\t\t\tcnt = flow_dv_counter_get_by_idx(dev,\n+\t\t\t\t(uint32_t)(uintptr_t)action->conf, NULL);\n+\t\t\tMLX5_ASSERT(cnt != NULL);\n+\t\t\tdev_flow->dv.actions[actions_n++] = cnt->action;\n+\t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:\n \t\t\tdev_flow->dv.actions[actions_n++] =\n \t\t\t\t\t\tpriv->sh->pop_vlan_action;\n@@ -11538,6 +11546,11 @@ flow_dv_translate(struct rte_eth_dev *dev,\n \t\t\t/* If decap is followed by encap, handle it at encap. */\n \t\t\taction_flags |= MLX5_FLOW_ACTION_DECAP;\n \t\t\tbreak;\n+\t\tcase MLX5_RTE_FLOW_ACTION_TYPE_JUMP:\n+\t\t\tdev_flow->dv.actions[actions_n++] =\n+\t\t\t\t(void *)(uintptr_t)action->conf;\n+\t\t\taction_flags |= MLX5_FLOW_ACTION_JUMP;\n+\t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_JUMP:\n \t\t\tjump_group = ((const struct rte_flow_action_jump *)\n \t\t\t\t\t\t\taction->conf)->group;\n@@ -12093,6 +12106,8 @@ flow_dv_translate(struct rte_eth_dev *dev,\n \t}\n \tdev_flow->dv.actions_n = actions_n;\n \tdev_flow->act_flags = action_flags;\n+\tif (wks->skip_matcher_reg)\n+\t\treturn 0;\n \t/* Register matcher. */\n \tmatcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,\n \t\t\t\t    matcher.mask.size);\n",
    "prefixes": [
        "v6",
        "4/4"
    ]
}