get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 62697,
    "url": "https://patches.dpdk.org/api/patches/62697/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1573146604-17803-20-git-send-email-viacheslavo@mellanox.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": "<1573146604-17803-20-git-send-email-viacheslavo@mellanox.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1573146604-17803-20-git-send-email-viacheslavo@mellanox.com",
    "date": "2019-11-07T17:10:04",
    "name": "[v3,19/19] net/mlx5: add metadata register copy table",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "6ccd9ae1965eeefa319d0cc616f1e3c54170e232",
    "submitter": {
        "id": 1102,
        "url": "https://patches.dpdk.org/api/people/1102/?format=api",
        "name": "Slava Ovsiienko",
        "email": "viacheslavo@mellanox.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/1573146604-17803-20-git-send-email-viacheslavo@mellanox.com/mbox/",
    "series": [
        {
            "id": 7336,
            "url": "https://patches.dpdk.org/api/series/7336/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=7336",
            "date": "2019-11-07T17:09:46",
            "name": "net/mlx5: implement extensive metadata feature",
            "version": 3,
            "mbox": "https://patches.dpdk.org/series/7336/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/62697/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/62697/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 dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 65B81A034E;\n\tThu,  7 Nov 2019 18:13:19 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 5DADC1C06B;\n\tThu,  7 Nov 2019 18:10:52 +0100 (CET)",
            "from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n by dpdk.org (Postfix) with ESMTP id 6B2D11BFEF\n for <dev@dpdk.org>; Thu,  7 Nov 2019 18:10:37 +0100 (CET)",
            "from Internal Mail-Server by MTLPINE1 (envelope-from\n viacheslavo@mellanox.com)\n with ESMTPS (AES256-SHA encrypted); 7 Nov 2019 19:10:33 +0200",
            "from pegasus11.mtr.labs.mlnx (pegasus11.mtr.labs.mlnx\n [10.210.16.104])\n by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xA7HAXpX024370;\n Thu, 7 Nov 2019 19:10:33 +0200",
            "from pegasus11.mtr.labs.mlnx (localhost [127.0.0.1])\n by pegasus11.mtr.labs.mlnx (8.14.7/8.14.7) with ESMTP id xA7HAXPE017980;\n Thu, 7 Nov 2019 17:10:33 GMT",
            "(from viacheslavo@localhost)\n by pegasus11.mtr.labs.mlnx (8.14.7/8.14.7/Submit) id xA7HAX64017979;\n Thu, 7 Nov 2019 17:10:33 GMT"
        ],
        "X-Authentication-Warning": "pegasus11.mtr.labs.mlnx: viacheslavo set sender to\n viacheslavo@mellanox.com using -f",
        "From": "Viacheslav Ovsiienko <viacheslavo@mellanox.com>",
        "To": "dev@dpdk.org",
        "Cc": "matan@mellanox.com, rasland@mellanox.com, thomas@monjalon.net,\n orika@mellanox.com, Yongseok Koh <yskoh@mellanox.com>",
        "Date": "Thu,  7 Nov 2019 17:10:04 +0000",
        "Message-Id": "<1573146604-17803-20-git-send-email-viacheslavo@mellanox.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1573146604-17803-1-git-send-email-viacheslavo@mellanox.com>",
        "References": "<1572940915-29416-1-git-send-email-viacheslavo@mellanox.com>\n <1573146604-17803-1-git-send-email-viacheslavo@mellanox.com>",
        "Subject": "[dpdk-dev] [PATCH v3 19/19] net/mlx5: add metadata register copy\n\ttable",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "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": "While reg_c[meta] can be copied to reg_b simply by modify-header\naction (it is supported by hardware), it is not possible to copy\nreg_c[mark] to the STE flow_tag as flow_tag is not a metadata\nregister and this is not supported by hardware. Instead, it\nshould be manually set by a flow per each unique MARK ID. For\nthis purpose, there should be a dedicated flow table -\nRX_CP_TBL and all the Rx flow should pass by the table\nto properly copy values from the register to flow tag field.\n\nAnd for each MARK action, a copy flow should be added\nto RX_CP_TBL according to the MARK ID like:\n  (if reg_c[mark] == mark_id),\n    flow_tag := mark_id / reg_b := reg_c[meta] / jump to RX_ACT_TBL\n\nFor SET_META action, there can be only one default flow like:\n  reg_b := reg_c[meta] / jump to RX_ACT_TBL\n\nSigned-off-by: Yongseok Koh <yskoh@mellanox.com>\nSigned-off-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>\nAcked-by: Matan Azrad <matan@mellanox.com>\n---\n drivers/net/mlx5/mlx5.c         |  15 ++\n drivers/net/mlx5/mlx5.h         |   7 +-\n drivers/net/mlx5/mlx5_defs.h    |   4 +\n drivers/net/mlx5/mlx5_flow.c    | 443 +++++++++++++++++++++++++++++++++++++++-\n drivers/net/mlx5/mlx5_flow.h    |  19 ++\n drivers/net/mlx5/mlx5_flow_dv.c |  10 +-\n 6 files changed, 491 insertions(+), 7 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 6359bc9..32e5fe5 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -1039,6 +1039,8 @@ struct mlx5_flow_id_pool *\n \t\tpriv->txqs = NULL;\n \t}\n \tmlx5_proc_priv_uninit(dev);\n+\tif (priv->mreg_cp_tbl)\n+\t\tmlx5_hlist_destroy(priv->mreg_cp_tbl, NULL, NULL);\n \tmlx5_mprq_free_mp(dev);\n \tmlx5_free_shared_dr(priv);\n \tif (priv->rss_conf.rss_key != NULL)\n@@ -2458,9 +2460,22 @@ struct mlx5_flow_id_pool *\n \t\t\tgoto error;\n \t\t}\n \t}\n+\tif (priv->config.dv_flow_en &&\n+\t    priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&\n+\t    mlx5_flow_ext_mreg_supported(eth_dev) &&\n+\t    priv->sh->dv_regc0_mask) {\n+\t\tpriv->mreg_cp_tbl = mlx5_hlist_create(MLX5_FLOW_MREG_HNAME,\n+\t\t\t\t\t\t      MLX5_FLOW_MREG_HTABLE_SZ);\n+\t\tif (!priv->mreg_cp_tbl) {\n+\t\t\terr = ENOMEM;\n+\t\t\tgoto error;\n+\t\t}\n+\t}\n \treturn eth_dev;\n error:\n \tif (priv) {\n+\t\tif (priv->mreg_cp_tbl)\n+\t\t\tmlx5_hlist_destroy(priv->mreg_cp_tbl, NULL, NULL);\n \t\tif (priv->sh)\n \t\t\tmlx5_free_shared_dr(priv);\n \t\tif (priv->nl_socket_route >= 0)\ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex 9c1a88a..619590b 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -567,8 +567,9 @@ struct mlx5_flow_tbl_resource {\n #define MLX5_HAIRPIN_TX_TABLE (UINT16_MAX - 1)\n /* Reserve the last two tables for metadata register copy. */\n #define MLX5_FLOW_MREG_ACT_TABLE_GROUP (MLX5_MAX_TABLES - 1)\n-#define MLX5_FLOW_MREG_CP_TABLE_GROUP \\\n-\t(MLX5_FLOW_MREG_ACT_TABLE_GROUP - 1)\n+#define MLX5_FLOW_MREG_CP_TABLE_GROUP (MLX5_MAX_TABLES - 2)\n+/* Tables for metering splits should be added here. */\n+#define MLX5_MAX_TABLES_EXTERNAL (MLX5_MAX_TABLES - 3)\n #define MLX5_MAX_TABLES_FDB UINT16_MAX\n \n #define MLX5_DBR_PAGE_SIZE 4096 /* Must be >= 512. */\n@@ -734,6 +735,8 @@ struct mlx5_priv {\n \tLIST_HEAD(dbrpage, mlx5_devx_dbr_page) dbrpgs; /* Door-bell pages. */\n \tstruct mlx5_vlan_vmwa_context *vmwa_context; /* VLAN WA context. */\n \tstruct mlx5_flow_id_pool *qrss_id_pool;\n+\tstruct mlx5_hlist *mreg_cp_tbl;\n+\t/* Hash table of Rx metadata register copy table. */\n #ifndef RTE_ARCH_64\n \trte_spinlock_t uar_lock_cq; /* CQs share a common distinct UAR */\n \trte_spinlock_t uar_lock[MLX5_UAR_PAGE_NUM_MAX];\ndiff --git a/drivers/net/mlx5/mlx5_defs.h b/drivers/net/mlx5/mlx5_defs.h\nindex a77c430..0ef532f 100644\n--- a/drivers/net/mlx5/mlx5_defs.h\n+++ b/drivers/net/mlx5/mlx5_defs.h\n@@ -145,6 +145,10 @@\n #define MLX5_XMETA_MODE_META16 1\n #define MLX5_XMETA_MODE_META32 2\n \n+/* Size of the simple hash table for metadata register table. */\n+#define MLX5_FLOW_MREG_HTABLE_SZ 4096\n+#define MLX5_FLOW_MREG_HNAME \"MARK_COPY_TABLE\"\n+\n /* Definition of static_assert found in /usr/include/assert.h */\n #ifndef HAVE_STATIC_ASSERT\n #define static_assert _Static_assert\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex 2f6ace0..9ef7f7d 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -671,7 +671,17 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,\n \t\t\tcontainer_of((*priv->rxqs)[idx],\n \t\t\t\t     struct mlx5_rxq_ctrl, rxq);\n \n-\t\tif (mark) {\n+\t\t/*\n+\t\t * To support metadata register copy on Tx loopback,\n+\t\t * this must be always enabled (metadata may arive\n+\t\t * from other port - not from local flows only.\n+\t\t */\n+\t\tif (priv->config.dv_flow_en &&\n+\t\t    priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&\n+\t\t    mlx5_flow_ext_mreg_supported(dev)) {\n+\t\t\trxq_ctrl->rxq.mark = 1;\n+\t\t\trxq_ctrl->flow_mark_n = 1;\n+\t\t} else if (mark) {\n \t\t\trxq_ctrl->rxq.mark = 1;\n \t\t\trxq_ctrl->flow_mark_n++;\n \t\t}\n@@ -735,7 +745,12 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,\n \t\t\tcontainer_of((*priv->rxqs)[idx],\n \t\t\t\t     struct mlx5_rxq_ctrl, rxq);\n \n-\t\tif (mark) {\n+\t\tif (priv->config.dv_flow_en &&\n+\t\t    priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&\n+\t\t    mlx5_flow_ext_mreg_supported(dev)) {\n+\t\t\trxq_ctrl->rxq.mark = 1;\n+\t\t\trxq_ctrl->flow_mark_n = 1;\n+\t\t} else if (mark) {\n \t\t\trxq_ctrl->flow_mark_n--;\n \t\t\trxq_ctrl->rxq.mark = !!rxq_ctrl->flow_mark_n;\n \t\t}\n@@ -2731,6 +2746,398 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,\n \treturn 0;\n }\n \n+/* Declare flow create/destroy prototype in advance. */\n+static struct rte_flow *\n+flow_list_create(struct rte_eth_dev *dev, struct mlx5_flows *list,\n+\t\t const struct rte_flow_attr *attr,\n+\t\t const struct rte_flow_item items[],\n+\t\t const struct rte_flow_action actions[],\n+\t\t bool external, struct rte_flow_error *error);\n+\n+static void\n+flow_list_destroy(struct rte_eth_dev *dev, struct mlx5_flows *list,\n+\t\t  struct rte_flow *flow);\n+\n+/**\n+ * Add a flow of copying flow metadata registers in RX_CP_TBL.\n+ *\n+ * As mark_id is unique, if there's already a registered flow for the mark_id,\n+ * return by increasing the reference counter of the resource. Otherwise, create\n+ * the resource (mcp_res) and flow.\n+ *\n+ * Flow looks like,\n+ *   - If ingress port is ANY and reg_c[1] is mark_id,\n+ *     flow_tag := mark_id, reg_b := reg_c[0] and jump to RX_ACT_TBL.\n+ *\n+ * For default flow (zero mark_id), flow is like,\n+ *   - If ingress port is ANY,\n+ *     reg_b := reg_c[0] and jump to RX_ACT_TBL.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @param mark_id\n+ *   ID of MARK action, zero means default flow for META.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ *\n+ * @return\n+ *   Associated resource on success, NULL otherwise and rte_errno is set.\n+ */\n+static struct mlx5_flow_mreg_copy_resource *\n+flow_mreg_add_copy_action(struct rte_eth_dev *dev, uint32_t mark_id,\n+\t\t\t  struct rte_flow_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct rte_flow_attr attr = {\n+\t\t.group = MLX5_FLOW_MREG_CP_TABLE_GROUP,\n+\t\t.ingress = 1,\n+\t};\n+\tstruct mlx5_rte_flow_item_tag tag_spec = {\n+\t\t.data = mark_id,\n+\t};\n+\tstruct rte_flow_item items[] = {\n+\t\t[1] = { .type = RTE_FLOW_ITEM_TYPE_END, },\n+\t};\n+\tstruct rte_flow_action_mark ftag = {\n+\t\t.id = mark_id,\n+\t};\n+\tstruct mlx5_flow_action_copy_mreg cp_mreg = {\n+\t\t.dst = REG_B,\n+\t\t.src = 0,\n+\t};\n+\tstruct rte_flow_action_jump jump = {\n+\t\t.group = MLX5_FLOW_MREG_ACT_TABLE_GROUP,\n+\t};\n+\tstruct rte_flow_action actions[] = {\n+\t\t[3] = { .type = RTE_FLOW_ACTION_TYPE_END, },\n+\t};\n+\tstruct mlx5_flow_mreg_copy_resource *mcp_res;\n+\tint ret;\n+\n+\t/* Fill the register fileds in the flow. */\n+\tret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);\n+\tif (ret < 0)\n+\t\treturn NULL;\n+\ttag_spec.id = ret;\n+\tret = mlx5_flow_get_reg_id(dev, MLX5_METADATA_RX, 0, error);\n+\tif (ret < 0)\n+\t\treturn NULL;\n+\tcp_mreg.src = ret;\n+\t/* Check if already registered. */\n+\tassert(priv->mreg_cp_tbl);\n+\tmcp_res = (void *)mlx5_hlist_lookup(priv->mreg_cp_tbl, mark_id);\n+\tif (mcp_res) {\n+\t\t/* For non-default rule. */\n+\t\tif (mark_id)\n+\t\t\tmcp_res->refcnt++;\n+\t\tassert(mark_id || mcp_res->refcnt == 1);\n+\t\treturn mcp_res;\n+\t}\n+\t/* Provide the full width of FLAG specific value. */\n+\tif (mark_id == (priv->sh->dv_regc0_mask & MLX5_FLOW_MARK_DEFAULT))\n+\t\ttag_spec.data = MLX5_FLOW_MARK_DEFAULT;\n+\t/* Build a new flow. */\n+\tif (mark_id) {\n+\t\titems[0] = (struct rte_flow_item){\n+\t\t\t.type = MLX5_RTE_FLOW_ITEM_TYPE_TAG,\n+\t\t\t.spec = &tag_spec,\n+\t\t};\n+\t\titems[1] = (struct rte_flow_item){\n+\t\t\t.type = RTE_FLOW_ITEM_TYPE_END,\n+\t\t};\n+\t\tactions[0] = (struct rte_flow_action){\n+\t\t\t.type = MLX5_RTE_FLOW_ACTION_TYPE_MARK,\n+\t\t\t.conf = &ftag,\n+\t\t};\n+\t\tactions[1] = (struct rte_flow_action){\n+\t\t\t.type = MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG,\n+\t\t\t.conf = &cp_mreg,\n+\t\t};\n+\t\tactions[2] = (struct rte_flow_action){\n+\t\t\t.type = RTE_FLOW_ACTION_TYPE_JUMP,\n+\t\t\t.conf = &jump,\n+\t\t};\n+\t\tactions[3] = (struct rte_flow_action){\n+\t\t\t.type = RTE_FLOW_ACTION_TYPE_END,\n+\t\t};\n+\t} else {\n+\t\t/* Default rule, wildcard match. */\n+\t\tattr.priority = MLX5_FLOW_PRIO_RSVD;\n+\t\titems[0] = (struct rte_flow_item){\n+\t\t\t.type = RTE_FLOW_ITEM_TYPE_END,\n+\t\t};\n+\t\tactions[0] = (struct rte_flow_action){\n+\t\t\t.type = MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG,\n+\t\t\t.conf = &cp_mreg,\n+\t\t};\n+\t\tactions[1] = (struct rte_flow_action){\n+\t\t\t.type = RTE_FLOW_ACTION_TYPE_JUMP,\n+\t\t\t.conf = &jump,\n+\t\t};\n+\t\tactions[2] = (struct rte_flow_action){\n+\t\t\t.type = RTE_FLOW_ACTION_TYPE_END,\n+\t\t};\n+\t}\n+\t/* Build a new entry. */\n+\tmcp_res = rte_zmalloc(__func__, sizeof(*mcp_res), 0);\n+\tif (!mcp_res) {\n+\t\trte_errno = ENOMEM;\n+\t\treturn NULL;\n+\t}\n+\t/*\n+\t * The copy Flows are not included in any list. There\n+\t * ones are referenced from other Flows and can not\n+\t * be applied, removed, deleted in ardbitrary order\n+\t * by list traversing.\n+\t */\n+\tmcp_res->flow = flow_list_create(dev, NULL, &attr, items,\n+\t\t\t\t\t actions, false, error);\n+\tif (!mcp_res->flow)\n+\t\tgoto error;\n+\tmcp_res->refcnt++;\n+\tmcp_res->hlist_ent.key = mark_id;\n+\tret = mlx5_hlist_insert(priv->mreg_cp_tbl,\n+\t\t\t\t&mcp_res->hlist_ent);\n+\tassert(!ret);\n+\tif (ret)\n+\t\tgoto error;\n+\treturn mcp_res;\n+error:\n+\tif (mcp_res->flow)\n+\t\tflow_list_destroy(dev, NULL, mcp_res->flow);\n+\trte_free(mcp_res);\n+\treturn NULL;\n+}\n+\n+/**\n+ * Release flow in RX_CP_TBL.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @flow\n+ *   Parent flow for wich copying is provided.\n+ */\n+static void\n+flow_mreg_del_copy_action(struct rte_eth_dev *dev,\n+\t\t\t  struct rte_flow *flow)\n+{\n+\tstruct mlx5_flow_mreg_copy_resource *mcp_res = flow->mreg_copy;\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\n+\tif (!mcp_res || !priv->mreg_cp_tbl)\n+\t\treturn;\n+\tif (flow->copy_applied) {\n+\t\tassert(mcp_res->appcnt);\n+\t\tflow->copy_applied = 0;\n+\t\t--mcp_res->appcnt;\n+\t\tif (!mcp_res->appcnt)\n+\t\t\tflow_drv_remove(dev, mcp_res->flow);\n+\t}\n+\t/*\n+\t * We do not check availability of metadata registers here,\n+\t * because copy resources are allocated in this case.\n+\t */\n+\tif (--mcp_res->refcnt)\n+\t\treturn;\n+\tassert(mcp_res->flow);\n+\tflow_list_destroy(dev, NULL, mcp_res->flow);\n+\tmlx5_hlist_remove(priv->mreg_cp_tbl, &mcp_res->hlist_ent);\n+\trte_free(mcp_res);\n+\tflow->mreg_copy = NULL;\n+}\n+\n+/**\n+ * Start flow in RX_CP_TBL.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @flow\n+ *   Parent flow for wich copying is provided.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+flow_mreg_start_copy_action(struct rte_eth_dev *dev,\n+\t\t\t    struct rte_flow *flow)\n+{\n+\tstruct mlx5_flow_mreg_copy_resource *mcp_res = flow->mreg_copy;\n+\tint ret;\n+\n+\tif (!mcp_res || flow->copy_applied)\n+\t\treturn 0;\n+\tif (!mcp_res->appcnt) {\n+\t\tret = flow_drv_apply(dev, mcp_res->flow, NULL);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\t++mcp_res->appcnt;\n+\tflow->copy_applied = 1;\n+\treturn 0;\n+}\n+\n+/**\n+ * Stop flow in RX_CP_TBL.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @flow\n+ *   Parent flow for wich copying is provided.\n+ */\n+static void\n+flow_mreg_stop_copy_action(struct rte_eth_dev *dev,\n+\t\t\t   struct rte_flow *flow)\n+{\n+\tstruct mlx5_flow_mreg_copy_resource *mcp_res = flow->mreg_copy;\n+\n+\tif (!mcp_res || !flow->copy_applied)\n+\t\treturn;\n+\tassert(mcp_res->appcnt);\n+\t--mcp_res->appcnt;\n+\tflow->copy_applied = 0;\n+\tif (!mcp_res->appcnt)\n+\t\tflow_drv_remove(dev, mcp_res->flow);\n+}\n+\n+/**\n+ * Remove the default copy action from RX_CP_TBL.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ */\n+static void\n+flow_mreg_del_default_copy_action(struct rte_eth_dev *dev)\n+{\n+\tstruct mlx5_flow_mreg_copy_resource *mcp_res;\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\n+\t/* Check if default flow is registered. */\n+\tif (!priv->mreg_cp_tbl)\n+\t\treturn;\n+\tmcp_res = (void *)mlx5_hlist_lookup(priv->mreg_cp_tbl, 0ULL);\n+\tif (!mcp_res)\n+\t\treturn;\n+\tassert(mcp_res->flow);\n+\tflow_list_destroy(dev, NULL, mcp_res->flow);\n+\tmlx5_hlist_remove(priv->mreg_cp_tbl, &mcp_res->hlist_ent);\n+\trte_free(mcp_res);\n+}\n+\n+/**\n+ * Add the default copy action in in RX_CP_TBL.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ *\n+ * @return\n+ *   0 for success, negative value otherwise and rte_errno is set.\n+ */\n+static int\n+flow_mreg_add_default_copy_action(struct rte_eth_dev *dev,\n+\t\t\t\t  struct rte_flow_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_mreg_copy_resource *mcp_res;\n+\n+\t/* Check whether extensive metadata feature is engaged. */\n+\tif (!priv->config.dv_flow_en ||\n+\t    priv->config.dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||\n+\t    !mlx5_flow_ext_mreg_supported(dev) ||\n+\t    !priv->sh->dv_regc0_mask)\n+\t\treturn 0;\n+\tmcp_res = flow_mreg_add_copy_action(dev, 0, error);\n+\tif (!mcp_res)\n+\t\treturn -rte_errno;\n+\treturn 0;\n+}\n+\n+/**\n+ * Add a flow of copying flow metadata registers in RX_CP_TBL.\n+ *\n+ * All the flow having Q/RSS action should be split by\n+ * flow_mreg_split_qrss_prep() to pass by RX_CP_TBL. A flow in the RX_CP_TBL\n+ * performs the following,\n+ *   - CQE->flow_tag := reg_c[1] (MARK)\n+ *   - CQE->flow_table_metadata (reg_b) := reg_c[0] (META)\n+ * As CQE's flow_tag is not a register, it can't be simply copied from reg_c[1]\n+ * but there should be a flow per each MARK ID set by MARK action.\n+ *\n+ * For the aforementioned reason, if there's a MARK action in flow's action\n+ * list, a corresponding flow should be added to the RX_CP_TBL in order to copy\n+ * the MARK ID to CQE's flow_tag like,\n+ *   - If reg_c[1] is mark_id,\n+ *     flow_tag := mark_id, reg_b := reg_c[0] and jump to RX_ACT_TBL.\n+ *\n+ * For SET_META action which stores value in reg_c[0], as the destination is\n+ * also a flow metadata register (reg_b), adding a default flow is enough. Zero\n+ * MARK ID means the default flow. The default flow looks like,\n+ *   - For all flow, reg_b := reg_c[0] and jump to RX_ACT_TBL.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @param flow\n+ *   Pointer to flow structure.\n+ * @param[in] actions\n+ *   Pointer to the list of actions.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ *\n+ * @return\n+ *   0 on success, negative value otherwise and rte_errno is set.\n+ */\n+static int\n+flow_mreg_update_copy_table(struct rte_eth_dev *dev,\n+\t\t\t    struct rte_flow *flow,\n+\t\t\t    const struct rte_flow_action *actions,\n+\t\t\t    struct rte_flow_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_dev_config *config = &priv->config;\n+\tstruct mlx5_flow_mreg_copy_resource *mcp_res;\n+\tconst struct rte_flow_action_mark *mark;\n+\n+\t/* Check whether extensive metadata feature is engaged. */\n+\tif (!config->dv_flow_en ||\n+\t    config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||\n+\t    !mlx5_flow_ext_mreg_supported(dev) ||\n+\t    !priv->sh->dv_regc0_mask)\n+\t\treturn 0;\n+\t/* Find MARK action. */\n+\tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {\n+\t\tswitch (actions->type) {\n+\t\tcase RTE_FLOW_ACTION_TYPE_FLAG:\n+\t\t\tmcp_res = flow_mreg_add_copy_action\n+\t\t\t\t(dev, MLX5_FLOW_MARK_DEFAULT, error);\n+\t\t\tif (!mcp_res)\n+\t\t\t\treturn -rte_errno;\n+\t\t\tflow->mreg_copy = mcp_res;\n+\t\t\tif (dev->data->dev_started) {\n+\t\t\t\tmcp_res->appcnt++;\n+\t\t\t\tflow->copy_applied = 1;\n+\t\t\t}\n+\t\t\treturn 0;\n+\t\tcase RTE_FLOW_ACTION_TYPE_MARK:\n+\t\t\tmark = (const struct rte_flow_action_mark *)\n+\t\t\t\tactions->conf;\n+\t\t\tmcp_res =\n+\t\t\t\tflow_mreg_add_copy_action(dev, mark->id, error);\n+\t\t\tif (!mcp_res)\n+\t\t\t\treturn -rte_errno;\n+\t\t\tflow->mreg_copy = mcp_res;\n+\t\t\tif (dev->data->dev_started) {\n+\t\t\t\tmcp_res->appcnt++;\n+\t\t\t\tflow->copy_applied = 1;\n+\t\t\t}\n+\t\t\treturn 0;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n #define MLX5_MAX_SPLIT_ACTIONS 24\n #define MLX5_MAX_SPLIT_ITEMS 24\n \n@@ -3454,6 +3861,22 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,\n \t\tif (ret < 0)\n \t\t\tgoto error;\n \t}\n+\t/*\n+\t * Update the metadata register copy table. If extensive\n+\t * metadata feature is enabled and registers are supported\n+\t * we might create the extra rte_flow for each unique\n+\t * MARK/FLAG action ID.\n+\t *\n+\t * The table is updated for ingress Flows only, because\n+\t * the egress Flows belong to the different device and\n+\t * copy table should be updated in peer NIC Rx domain.\n+\t */\n+\tif (attr->ingress &&\n+\t    (external || attr->group != MLX5_FLOW_MREG_CP_TABLE_GROUP)) {\n+\t\tret = flow_mreg_update_copy_table(dev, flow, actions, error);\n+\t\tif (ret)\n+\t\t\tgoto error;\n+\t}\n \tif (dev->data->dev_started) {\n \t\tret = flow_drv_apply(dev, flow, error);\n \t\tif (ret < 0)\n@@ -3469,6 +3892,8 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,\n \t\t\t\t     hairpin_id);\n \treturn NULL;\n error:\n+\tassert(flow);\n+\tflow_mreg_del_copy_action(dev, flow);\n \tret = rte_errno; /* Save rte_errno before cleanup. */\n \tif (flow->hairpin_flow_id)\n \t\tmlx5_flow_id_release(priv->sh->flow_id_pool,\n@@ -3577,6 +4002,7 @@ struct rte_flow *\n \tflow_drv_destroy(dev, flow);\n \tif (list)\n \t\tTAILQ_REMOVE(list, flow, next);\n+\tflow_mreg_del_copy_action(dev, flow);\n \trte_free(flow->fdir);\n \trte_free(flow);\n }\n@@ -3613,8 +4039,11 @@ struct rte_flow *\n {\n \tstruct rte_flow *flow;\n \n-\tTAILQ_FOREACH_REVERSE(flow, list, mlx5_flows, next)\n+\tTAILQ_FOREACH_REVERSE(flow, list, mlx5_flows, next) {\n \t\tflow_drv_remove(dev, flow);\n+\t\tflow_mreg_stop_copy_action(dev, flow);\n+\t}\n+\tflow_mreg_del_default_copy_action(dev);\n \tflow_rxq_flags_clear(dev);\n }\n \n@@ -3636,7 +4065,15 @@ struct rte_flow *\n \tstruct rte_flow_error error;\n \tint ret = 0;\n \n+\t/* Make sure default copy action (reg_c[0] -> reg_b) is created. */\n+\tret = flow_mreg_add_default_copy_action(dev, &error);\n+\tif (ret < 0)\n+\t\treturn -rte_errno;\n+\t/* Apply Flows created by application. */\n \tTAILQ_FOREACH(flow, list, next) {\n+\t\tret = flow_mreg_start_copy_action(dev, flow);\n+\t\tif (ret < 0)\n+\t\t\tgoto error;\n \t\tret = flow_drv_apply(dev, flow, &error);\n \t\tif (ret < 0)\n \t\t\tgoto error;\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nindex c71938b..560b2b1 100644\n--- a/drivers/net/mlx5/mlx5_flow.h\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -38,6 +38,7 @@ enum mlx5_rte_flow_item_type {\n enum mlx5_rte_flow_action_type {\n \tMLX5_RTE_FLOW_ACTION_TYPE_END = INT_MIN,\n \tMLX5_RTE_FLOW_ACTION_TYPE_TAG,\n+\tMLX5_RTE_FLOW_ACTION_TYPE_MARK,\n \tMLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG,\n };\n \n@@ -417,6 +418,21 @@ struct mlx5_flow_dv_push_vlan_action_resource {\n \trte_be32_t vlan_tag; /**< VLAN tag value. */\n };\n \n+/* Metadata register copy table entry. */\n+struct mlx5_flow_mreg_copy_resource {\n+\t/*\n+\t * Hash list entry for copy table.\n+\t *  - Key is 32/64-bit MARK action ID.\n+\t *  - MUST be the first entry.\n+\t */\n+\tstruct mlx5_hlist_entry hlist_ent;\n+\tLIST_ENTRY(mlx5_flow_mreg_copy_resource) next;\n+\t/* List entry for device flows. */\n+\tuint32_t refcnt; /* Reference counter. */\n+\tuint32_t appcnt; /* Apply/Remove counter. */\n+\tstruct rte_flow *flow; /* Built flow for copy. */\n+};\n+\n /*\n  * Max number of actions per DV flow.\n  * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED\n@@ -510,10 +526,13 @@ struct rte_flow {\n \tenum mlx5_flow_drv_type drv_type; /**< Driver type. */\n \tstruct mlx5_flow_rss rss; /**< RSS context. */\n \tstruct mlx5_flow_counter *counter; /**< Holds flow counter. */\n+\tstruct mlx5_flow_mreg_copy_resource *mreg_copy;\n+\t/**< pointer to metadata register copy table resource. */\n \tLIST_HEAD(dev_flows, mlx5_flow) dev_flows;\n \t/**< Device flows that are part of the flow. */\n \tstruct mlx5_fdir *fdir; /**< Pointer to associated FDIR if any. */\n \tuint32_t hairpin_flow_id; /**< The flow id used for hairpin. */\n+\tuint32_t copy_applied:1; /**< The MARK copy Flow os applied. */\n };\n \n typedef int (*mlx5_flow_validate_t)(struct rte_eth_dev *dev,\ndiff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c\nindex 60ebbca..f06227c 100644\n--- a/drivers/net/mlx5/mlx5_flow_dv.c\n+++ b/drivers/net/mlx5/mlx5_flow_dv.c\n@@ -4086,8 +4086,11 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\t\t  NULL,\n \t\t\t\t\t  \"groups are not supported\");\n #else\n-\tuint32_t max_group = attributes->transfer ? MLX5_MAX_TABLES_FDB :\n-\t\t\t\t\t\t    MLX5_MAX_TABLES;\n+\tuint32_t max_group = attributes->transfer ?\n+\t\t\t     MLX5_MAX_TABLES_FDB :\n+\t\t\t\texternal ?\n+\t\t\t\tMLX5_MAX_TABLES_EXTERNAL :\n+\t\t\t\tMLX5_MAX_TABLES;\n \tuint32_t table;\n \tint ret;\n \n@@ -4694,6 +4697,7 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\t\t\tMLX5_FLOW_ACTION_DEC_TCP_ACK;\n \t\t\tbreak;\n \t\tcase MLX5_RTE_FLOW_ACTION_TYPE_TAG:\n+\t\tcase MLX5_RTE_FLOW_ACTION_TYPE_MARK:\n \t\tcase MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:\n \t\t\tbreak;\n \t\tdefault:\n@@ -6530,6 +6534,8 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\taction_flags |= MLX5_FLOW_ACTION_MARK_EXT;\n \t\t\t\tbreak;\n \t\t\t}\n+\t\t\t/* Fall-through */\n+\t\tcase MLX5_RTE_FLOW_ACTION_TYPE_MARK:\n \t\t\t/* Legacy (non-extensive) MARK action. */\n \t\t\ttag_resource.tag = mlx5_flow_mark_set\n \t\t\t      (((const struct rte_flow_action_mark *)\n",
    "prefixes": [
        "v3",
        "19/19"
    ]
}