get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 76930,
    "url": "http://patches.dpdk.org/api/patches/76930/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200908201552.14423-4-getelson@nvidia.com/",
    "project": {
        "id": 1,
        "url": "http://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": "<20200908201552.14423-4-getelson@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200908201552.14423-4-getelson@nvidia.com",
    "date": "2020-09-08T20:15:50",
    "name": "[v2,3/4] net/mlx5: implement tunnel offload API",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b383793cfe88b1f051287fb2a8ddf2f38a4cad23",
    "submitter": {
        "id": 1882,
        "url": "http://patches.dpdk.org/api/people/1882/?format=api",
        "name": "Gregory Etelson",
        "email": "getelson@nvidia.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20200908201552.14423-4-getelson@nvidia.com/mbox/",
    "series": [
        {
            "id": 12033,
            "url": "http://patches.dpdk.org/api/series/12033/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=12033",
            "date": "2020-09-08T20:15:47",
            "name": "Tunnel Offload API",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/12033/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/76930/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/76930/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 EE870A04B1;\n\tTue,  8 Sep 2020 22:16:40 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id E85EB1C0CC;\n\tTue,  8 Sep 2020 22:16:38 +0200 (CEST)",
            "from hqnvemgate24.nvidia.com (hqnvemgate24.nvidia.com\n [216.228.121.143]) by dpdk.org (Postfix) with ESMTP id 6EAC11C0CA\n for <dev@dpdk.org>; Tue,  8 Sep 2020 22:16:37 +0200 (CEST)",
            "from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by\n hqnvemgate24.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA)\n id <B5f57e61e0000>; Tue, 08 Sep 2020 13:14:22 -0700",
            "from hqmail.nvidia.com ([172.20.161.6])\n by hqpgpgate101.nvidia.com (PGP Universal service);\n Tue, 08 Sep 2020 13:16:36 -0700",
            "from nvidia.com (10.124.1.5) by HQMAIL107.nvidia.com (172.20.187.13)\n with Microsoft SMTP Server (TLS) id 15.0.1473.3;\n Tue, 8 Sep 2020 20:16:24 +0000"
        ],
        "X-PGP-Universal": "processed;\n by hqpgpgate101.nvidia.com on Tue, 08 Sep 2020 13:16:36 -0700",
        "From": "Gregory Etelson <getelson@nvidia.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<matan@nvidia.com>, <rasland@nvidia.com>, <orika@nvidia.com>, \"Gregory\n Etelson\" <getelson@mellanox.com>, Matan Azrad <matan@mellanox.com>, \"Shahaf\n Shuler\" <shahafs@mellanox.com>, Viacheslav Ovsiienko\n <viacheslavo@mellanox.com>",
        "Date": "Tue, 8 Sep 2020 23:15:50 +0300",
        "Message-ID": "<20200908201552.14423-4-getelson@nvidia.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20200908201552.14423-1-getelson@nvidia.com>",
        "References": "<20200625160348.26220-1-getelson@mellanox.com>\n <20200908201552.14423-1-getelson@nvidia.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "quoted-printable",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.124.1.5]",
        "X-ClientProxiedBy": "HQMAIL101.nvidia.com (172.20.187.10) To\n HQMAIL107.nvidia.com (172.20.187.13)",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1;\n t=1599596062; bh=uww4QF0BkH49v0Zl+JIsZCTHy64erI0NDc1li8HR5x4=;\n h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer:\n In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:\n Content-Type:X-Originating-IP:X-ClientProxiedBy;\n b=isqlcKU24i2yb9rCSDKHhnOGUTeeJ1F+pd7w3BoXwYw+X+/y2MGpTrT4xZHbraPv5\n NZgaeYFXaEih2CAIyEurkF3N+rHFHALZKJD7nLTlvlkQX1xwTK1ho8ovLralxYHDDm\n FOk+c1k/P1mAbGQhxP75DHKzxEfqGTi2+d2f5gxLCoSoKmTcw3JNT2U4sz/wDZ3Uan\n /94erOL97rBVGzXQg4s4M54xFqHNVcZDrob2bmlcXe/yhp3Kgvn8OM2i33BM/3u3q8\n vpu6aQBwTHcoC5fJMj5zjvi+4SI0aMx2nn4RZhoLJcKetd7iCZAJP58CHZiCkxLj5b\n fZW9GdkqBxgyQ==",
        "Subject": "[dpdk-dev] [PATCH v2 3/4] net/mlx5: implement tunnel offload API",
        "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": "From: Gregory Etelson <getelson@mellanox.com>\n\nTunnel Offload API provides hardware independent, unified model\nto offload tunneled traffic. Key model elements are:\n - apply matches to both outer and inner packet headers\n   during entire offload procedure;\n - restore outer header of partially offloaded packet;\n - model is implemented as a set of helper functions.\n\nImplementation details:\n* tunnel_offload PMD parameter must be set to 1 to enable the feature.\n* application cannot use MARK and META flow actions whith tunnel.\n* offload JUMP action is restricted to steering tunnel rule only.\n\nSigned-off-by: Gregory Etelson <getelson@mellanox.com>\n---\nv2:\n* introduce MLX5 PMD API implementation\n---\n drivers/net/mlx5/linux/mlx5_os.c |  14 +\n drivers/net/mlx5/mlx5.c          |   6 +\n drivers/net/mlx5/mlx5.h          |   4 +\n drivers/net/mlx5/mlx5_flow.c     | 453 +++++++++++++++++++++++++++++++\n drivers/net/mlx5/mlx5_flow.h     |  49 ++++\n drivers/net/mlx5/mlx5_flow_dv.c  |  71 ++++-\n 6 files changed, 595 insertions(+), 2 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c\nindex 69123e12c3..7193398750 100644\n--- a/drivers/net/mlx5/linux/mlx5_os.c\n+++ b/drivers/net/mlx5/linux/mlx5_os.c\n@@ -281,6 +281,12 @@ mlx5_alloc_shared_dr(struct mlx5_priv *priv)\n \t\tsh->esw_drop_action = mlx5_glue->dr_create_flow_action_drop();\n \t}\n #endif\n+\tif (!sh->tunnel_hub)\n+\t\terr = mlx5_alloc_tunnel_hub(sh);\n+\tif (err) {\n+\t\tDRV_LOG(ERR, \"mlx5_alloc_tunnel_hub failed err=%d\", err);\n+\t\tgoto error;\n+\t}\n \tif (priv->config.reclaim_mode == MLX5_RCM_AGGR) {\n \t\tmlx5_glue->dr_reclaim_domain_memory(sh->rx_domain, 1);\n \t\tmlx5_glue->dr_reclaim_domain_memory(sh->tx_domain, 1);\n@@ -319,6 +325,10 @@ mlx5_alloc_shared_dr(struct mlx5_priv *priv)\n \t\tmlx5_hlist_destroy(sh->tag_table, NULL, NULL);\n \t\tsh->tag_table = NULL;\n \t}\n+\tif (sh->tunnel_hub) {\n+\t\tmlx5_release_tunnel_hub(sh);\n+\t\tsh->tunnel_hub = NULL;\n+\t}\n \tmlx5_free_table_hash_list(priv);\n \treturn err;\n }\n@@ -372,6 +382,10 @@ mlx5_os_free_shared_dr(struct mlx5_priv *priv)\n \t\tmlx5_hlist_destroy(sh->tag_table, NULL, NULL);\n \t\tsh->tag_table = NULL;\n \t}\n+\tif (sh->tunnel_hub) {\n+\t\tmlx5_release_tunnel_hub(sh);\n+\t\tsh->tunnel_hub = NULL;\n+\t}\n \tmlx5_free_table_hash_list(priv);\n }\n \ndiff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 1e4c695f84..569070d3db 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -177,6 +177,9 @@\n /* Decap will be used or not. */\n #define MLX5_DECAP_EN \"decap_en\"\n \n+/* Configure flow tunnel offload functionality */\n+#define MLX5_TUNNEL_OFFLOAD \"tunnel_offload\"\n+\n /* Shared memory between primary and secondary processes. */\n struct mlx5_shared_data *mlx5_shared_data;\n \n@@ -1621,6 +1624,8 @@ mlx5_args_check(const char *key, const char *val, void *opaque)\n \t\tconfig->sys_mem_en = !!tmp;\n \t} else if (strcmp(MLX5_DECAP_EN, key) == 0) {\n \t\tconfig->decap_en = !!tmp;\n+\t} else if (strcmp(MLX5_TUNNEL_OFFLOAD, key) == 0) {\n+\t\tconfig->tunnel_offload = !!tmp;\n \t} else {\n \t\tDRV_LOG(WARNING, \"%s: unknown parameter\", key);\n \t\trte_errno = EINVAL;\n@@ -1681,6 +1686,7 @@ mlx5_args(struct mlx5_dev_config *config, struct rte_devargs *devargs)\n \t\tMLX5_RECLAIM_MEM,\n \t\tMLX5_SYS_MEM_EN,\n \t\tMLX5_DECAP_EN,\n+\t\tMLX5_TUNNEL_OFFLOAD,\n \t\tNULL,\n \t};\n \tstruct rte_kvargs *kvlist;\ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex 78d6eb7281..e450aec029 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -208,6 +208,7 @@ struct mlx5_dev_config {\n \tunsigned int rt_timestamp:1; /* realtime timestamp format. */\n \tunsigned int sys_mem_en:1; /* The default memory allocator. */\n \tunsigned int decap_en:1; /* Whether decap will be used or not. */\n+\tunsigned int tunnel_offload:1; /* Flow tunnel offload functionality */\n \tstruct {\n \t\tunsigned int enabled:1; /* Whether MPRQ is enabled. */\n \t\tunsigned int stride_num_n; /* Number of strides. */\n@@ -605,6 +606,7 @@ struct mlx5_dev_ctx_shared {\n \tLIST_ENTRY(mlx5_dev_ctx_shared) next;\n \tuint32_t refcnt;\n \tuint32_t devx:1; /* Opened with DV. */\n+\tuint32_t tunnel:1; /* 1 RTE flow tunnel enabled */\n \tuint32_t max_port; /* Maximal IB device port index. */\n \tvoid *ctx; /* Verbs/DV/DevX context. */\n \tvoid *pd; /* Protection Domain. */\n@@ -634,6 +636,8 @@ struct mlx5_dev_ctx_shared {\n \t/* UAR same-page access control required in 32bit implementations. */\n #endif\n \tstruct mlx5_hlist *flow_tbls;\n+\tstruct rte_hash *flow_tbl_map; /* app group-to-flow table map */\n+\tstruct mlx5_flow_tunnel_hub *tunnel_hub;\n \t/* Direct Rules tables for FDB, NIC TX+RX */\n \tvoid *esw_drop_action; /* Pointer to DR E-Switch drop action. */\n \tvoid *pop_vlan_action; /* Pointer to DR pop VLAN action. */\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex 71501730b5..7d4bddee39 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -18,6 +18,7 @@\n #include <rte_flow_driver.h>\n #include <rte_malloc.h>\n #include <rte_ip.h>\n+#include <rte_hash.h>\n \n #include <mlx5_glue.h>\n #include <mlx5_devx_cmds.h>\n@@ -30,6 +31,13 @@\n #include \"mlx5_flow_os.h\"\n #include \"mlx5_rxtx.h\"\n \n+static struct mlx5_flow_tunnel *\n+mlx5_find_tunnel_id(struct rte_eth_dev *dev, uint32_t id);\n+static void\n+mlx5_flow_tunnel_free(struct rte_eth_dev *dev, struct mlx5_flow_tunnel *tunnel);\n+static uint32_t\n+mlx5_mark_to_tunnel_id(uint32_t mark);\n+\n /** Device flow drivers. */\n extern const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops;\n \n@@ -220,6 +228,169 @@ static const struct rte_flow_expand_node mlx5_support_expansion[] = {\n \t},\n };\n \n+static inline bool\n+mlx5_flow_tunnel_validate(__rte_unused struct rte_eth_dev *dev,\n+\t\t\t  struct rte_flow_tunnel *tunnel)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\n+\tif (!priv->config.tunnel_offload || !tunnel)\n+\t\tgoto err;\n+\n+\tswitch (tunnel->type) {\n+\tdefault:\n+\t\tgoto err;\n+\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\tbreak;\n+\t}\n+\n+\treturn true;\n+\n+err:\n+\treturn false;\n+}\n+\n+static int\n+mlx5_flow_tunnel_set(struct rte_eth_dev *dev,\n+\t\t    struct rte_flow_tunnel *app_tunnel,\n+\t\t    struct rte_flow_action **actions,\n+\t\t    uint32_t *num_of_actions,\n+\t\t    struct rte_flow_error *error)\n+{\n+\tint ret;\n+\tstruct mlx5_flow_tunnel *tunnel;\n+\tif (!mlx5_flow_tunnel_validate(dev, app_tunnel))\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,\n+\t\t\t\t\t  \"invalid argument\");\n+\n+\tret = mlx5_get_flow_tunnel(dev, app_tunnel, &tunnel);\n+\tif (ret < 0) {\n+\t\treturn rte_flow_error_set(error, ret,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,\n+\t\t\t\t\t  \"failed to match pmd tunnel\");\n+\t}\n+\trte_atomic32_inc(&tunnel->refctn);\n+\t*actions = &tunnel->action;\n+\t*num_of_actions = 1;\n+\treturn 0;\n+}\n+\n+static int\n+mlx5_flow_tunnel_match(struct rte_eth_dev *dev,\n+\t\t       struct rte_flow_tunnel *app_tunnel,\n+\t\t       struct rte_flow_item **items,\n+\t\t       uint32_t *num_of_items,\n+\t\t       struct rte_flow_error *error)\n+{\n+\tint ret;\n+\tstruct mlx5_flow_tunnel *tunnel;\n+\tif (!mlx5_flow_tunnel_validate(dev, app_tunnel))\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t\t  \"invalid argument\");\n+\n+\tret = mlx5_get_flow_tunnel(dev, app_tunnel, &tunnel);\n+\tif (ret < 0) {\n+\t\treturn rte_flow_error_set(error, ret,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t\t  \"failed to match pmd tunnel\");\n+\t}\n+\n+\trte_atomic32_inc(&tunnel->refctn);\n+\t*items = &tunnel->item;\n+\t*num_of_items = 1;\n+\treturn 0;\n+}\n+\n+static int\n+mlx5_flow_item_release(struct rte_eth_dev *dev,\n+\t\t       struct rte_flow_item *pmd_items,\n+\t\t       uint32_t num_items, struct rte_flow_error *err)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_dev_ctx_shared *sh = priv->sh;\n+\tstruct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;\n+\tstruct mlx5_flow_tunnel *tun;\n+\n+\tLIST_FOREACH(tun, &thub->tunnels, chain) {\n+\t\tif (&tun->item == pmd_items)\n+\t\t\tbreak;\n+\t}\n+\tif (!tun || num_items != 1)\n+\t\treturn rte_flow_error_set(err, EINVAL,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t\t  \"invalid argument\");\n+\tif (rte_atomic32_dec_and_test(&tun->refctn))\n+\t\tmlx5_flow_tunnel_free(dev, tun);\n+\treturn 0;\n+}\n+\n+static int\n+mlx5_flow_action_release(struct rte_eth_dev *dev,\n+\t\t\t struct rte_flow_action *pmd_actions,\n+\t\t\t uint32_t num_actions, struct rte_flow_error *err)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_dev_ctx_shared *sh = priv->sh;\n+\tstruct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;\n+\tstruct mlx5_flow_tunnel *tun;\n+\n+\tLIST_FOREACH(tun, &thub->tunnels, chain) {\n+\t\tif (&tun->action == pmd_actions)\n+\t\t\tbreak;\n+\t}\n+\tif (!tun || num_actions != 1)\n+\t\treturn rte_flow_error_set(err, EINVAL,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t\t  \"invalid argument\");\n+\tif (rte_atomic32_dec_and_test(&tun->refctn))\n+\t\tmlx5_flow_tunnel_free(dev, tun);\n+\n+\treturn 0;\n+}\n+\n+static void\n+mlx5_restore_packet_outer(struct rte_eth_dev *dev __rte_unused,\n+\t\t\t  struct mlx5_flow_tunnel *tunnel __rte_unused,\n+\t\t\t  struct rte_mbuf *m __rte_unused)\n+{\n+}\n+\n+static int\n+mlx5_flow_tunnel_get_restore_info(struct rte_eth_dev *dev,\n+\t\t\t\t  struct rte_mbuf *m,\n+\t\t\t\t  struct rte_flow_restore_info *info,\n+\t\t\t\t  struct rte_flow_error *err)\n+{\n+\tuint32_t id;\n+\tuint64_t ol_flags = m->ol_flags;\n+\tstruct mlx5_flow_tunnel *tunnel;\n+\tconst uint64_t mask = PKT_RX_FDIR | PKT_RX_FDIR_ID;\n+\n+\tif ((ol_flags & mask) != mask)\n+\t\tgoto err;\n+\tid = mlx5_mark_to_tunnel_id(m->hash.fdir.hi);\n+\tif (!id)\n+\t\tgoto err;\n+\ttunnel = mlx5_find_tunnel_id(dev, id);\n+\tif (!tunnel)\n+\t\tgoto err;\n+\tmlx5_restore_packet_outer(dev, tunnel, m);\n+\tmemcpy(&info->tunnel, &tunnel->app_tunnel, sizeof(info->tunnel));\n+\tm->ol_flags &= ~PKT_RX_FDIR;\n+\tinfo->group_id = -1u;\n+\tinfo->flags = RTE_FLOW_RESTORE_INFO_TUNNEL |\n+\t\t      RTE_FLOW_RESTORE_INFO_ENCAPSULATED;\n+\n+\treturn 0;\n+\n+err:\n+\treturn rte_flow_error_set(err, EINVAL,\n+\t\t\t\t  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t  \"failed to get restore info\");\n+}\n+\n static const struct rte_flow_ops mlx5_flow_ops = {\n \t.validate = mlx5_flow_validate,\n \t.create = mlx5_flow_create,\n@@ -229,6 +400,11 @@ static const struct rte_flow_ops mlx5_flow_ops = {\n \t.query = mlx5_flow_query,\n \t.dev_dump = mlx5_flow_dev_dump,\n \t.get_aged_flows = mlx5_flow_get_aged_flows,\n+\t.tunnel_decap_set = mlx5_flow_tunnel_set,\n+\t.tunnel_match = mlx5_flow_tunnel_match,\n+\t.action_release = mlx5_flow_action_release,\n+\t.item_release = mlx5_flow_item_release,\n+\t.get_restore_info = mlx5_flow_tunnel_get_restore_info,\n };\n \n /* Convert FDIR request to Generic flow. */\n@@ -3524,6 +3700,104 @@ flow_hairpin_split(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+static uint32_t\n+mlx5_tunnel_id_to_mark(uint32_t id)\n+{\n+\treturn (!id || id >= MLX5_MAX_TUNNELS) ?\n+\t\t0 : (id << 16);\n+}\n+\n+static uint32_t\n+mlx5_mark_to_tunnel_id(uint32_t mark)\n+{\n+\treturn mark & MLX5_TUNNEL_MARK_MASK ?\n+\t\tmark >> 16 : 0;\n+}\n+\n+static int\n+flow_tunnel_add_default_miss(struct rte_eth_dev *dev,\n+\t\t\t     struct rte_flow *flow,\n+\t\t\t     const struct rte_flow_attr *attr,\n+\t\t\t     const struct rte_flow_action *app_actions,\n+\t\t\t     uint32_t flow_idx,\n+\t\t\t     struct rte_flow_error *error)\n+{\n+\tstruct mlx5_flow *dev_flow;\n+\tstruct rte_flow_attr miss_attr = *attr;\n+\tconst struct mlx5_flow_tunnel *tunnel = app_actions[0].conf;\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tuint16_t queue[priv->reta_idx_n];\n+\tstruct rte_flow_action_rss action_rss = {\n+\t\t.func = RTE_ETH_HASH_FUNCTION_DEFAULT,\n+\t\t.level = 0,\n+\t\t.types = priv->rss_conf.rss_hf,\n+\t\t.key_len = priv->rss_conf.rss_key_len,\n+\t\t.queue_num = priv->reta_idx_n,\n+\t\t.key = priv->rss_conf.rss_key,\n+\t\t.queue = queue,\n+\t};\n+\tconst struct rte_flow_action_mark miss_mark = {\n+\t\t.id = mlx5_tunnel_id_to_mark(tunnel->tunnel_id)\n+\t};\n+\tconst struct rte_flow_item *items, miss_items[2] = {\n+\t\t{\n+\t\t\t.type = RTE_FLOW_ITEM_TYPE_ETH,\n+\t\t\t.spec = NULL,\n+\t\t\t.last = NULL,\n+\t\t\t.mask = NULL\n+\t\t},\n+\t\t{\n+\t\t\t.type = RTE_FLOW_ITEM_TYPE_END,\n+\t\t\t.spec = NULL,\n+\t\t\t.last = NULL,\n+\t\t\t.mask = NULL\n+\t\t}\n+\t};\n+\tconst struct rte_flow_action *actions, miss_actions[3] = {\n+\t\t{ .type = RTE_FLOW_ACTION_TYPE_MARK, .conf = &miss_mark },\n+\t\t{ .type = RTE_FLOW_ACTION_TYPE_RSS, .conf = &action_rss },\n+\t\t{ .type = RTE_FLOW_ACTION_TYPE_END, .conf = NULL }\n+\t};\n+\tconst struct rte_flow_action_jump *jump_data;\n+\tuint32_t i;\n+\n+\tif (!priv->reta_idx_n || !priv->rxqs_n)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ACTION_CONF,\n+\t\t\t\t   NULL, \"invalid port configuration\");\n+\tif (!(dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG))\n+\t\taction_rss.types = 0;\n+\tfor (i = 0; i != priv->reta_idx_n; ++i)\n+\t\tqueue[i] = (*priv->reta_idx)[i];\n+\n+\tif (!miss_mark.id)\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ACTION_CONF,\n+\t\t\t\t   NULL, \"invalid tunnel id\");\n+\titems = (typeof(items))miss_items;\n+\tactions = (typeof(actions))miss_actions;\n+\tfor (; app_actions->type != RTE_FLOW_ACTION_TYPE_JUMP; app_actions++);\n+\tjump_data = app_actions->conf;\n+\tmiss_attr.priority = 3;\n+\tmiss_attr.group = TUNNEL_STEER_GROUP(jump_data->group);\n+\tdev_flow = flow_drv_prepare(dev, flow, &miss_attr,\n+\t\t\t\t    items, actions, flow_idx, error);\n+\tif (!dev_flow)\n+\t\treturn -rte_errno;\n+\tdev_flow->flow = flow;\n+\tdev_flow->external = true;\n+\t/* Subflow object was created, we must include one in the list. */\n+\tSILIST_INSERT(&flow->dev_handles, dev_flow->handle_idx,\n+\t\t      dev_flow->handle, next);\n+\n+\tDRV_LOG(DEBUG,\n+\t\t\"port %u tunnel type=%d id=%u miss rule priority=%u group=%u\",\n+\t\tdev->data->port_id, tunnel->app_tunnel.type,\n+\t\ttunnel->tunnel_id, miss_attr.priority, miss_attr.group);\n+\treturn flow_drv_translate(dev, dev_flow, &miss_attr, items,\n+\t\t\t\t  actions, error);\n+}\n+\n /**\n  * The last stage of splitting chain, just creates the subflow\n  * without any modification.\n@@ -4296,6 +4570,27 @@ flow_create_split_outer(struct rte_eth_dev *dev,\n \treturn ret;\n }\n \n+static struct mlx5_flow_tunnel *\n+flow_tunnel_from_rule(struct rte_eth_dev *dev,\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+{\n+\tstruct mlx5_flow_tunnel *tunnel;\n+\n+#pragma GCC diagnostic push\n+#pragma GCC diagnostic ignored \"-Wcast-qual\"\n+\tif (is_flow_tunnel_match_rule(dev, attr, items, actions))\n+\t\ttunnel = (struct mlx5_flow_tunnel *)items[0].spec;\n+\telse if (is_flow_tunnel_steer_rule(dev, attr, items, actions))\n+\t\ttunnel = (struct mlx5_flow_tunnel *)actions[0].conf;\n+\telse\n+\t\ttunnel = NULL;\n+#pragma GCC diagnostic pop\n+\n+\treturn tunnel;\n+}\n+\n /**\n  * Create a flow and add it to @p list.\n  *\n@@ -4356,6 +4651,7 @@ flow_list_create(struct rte_eth_dev *dev, uint32_t *list,\n \tint hairpin_flow;\n \tuint32_t hairpin_id = 0;\n \tstruct rte_flow_attr attr_tx = { .priority = 0 };\n+\tstruct mlx5_flow_tunnel *tunnel;\n \tint ret;\n \n \thairpin_flow = flow_check_hairpin_split(dev, attr, actions);\n@@ -4430,6 +4726,15 @@ flow_list_create(struct rte_eth_dev *dev, uint32_t *list,\n \t\t\t\t\t      error);\n \t\tif (ret < 0)\n \t\t\tgoto error;\n+\t\tif (is_flow_tunnel_steer_rule(dev, attr,\n+\t\t\t\t\t      buf->entry[i].pattern,\n+\t\t\t\t\t      p_actions_rx)) {\n+\t\t\tret = flow_tunnel_add_default_miss(dev, flow, attr,\n+\t\t\t\t\t\t\t   p_actions_rx,\n+\t\t\t\t\t\t\t   idx, error);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto error;\n+\t\t}\n \t}\n \t/* Create the tx flow. */\n \tif (hairpin_flow) {\n@@ -4484,6 +4789,12 @@ flow_list_create(struct rte_eth_dev *dev, uint32_t *list,\n \tpriv->flow_idx = priv->flow_nested_idx;\n \tif (priv->flow_nested_idx)\n \t\tpriv->flow_nested_idx = 0;\n+\ttunnel = flow_tunnel_from_rule(dev, attr, items, actions);\n+\tif (tunnel) {\n+\t\tflow->tunnel = 1;\n+\t\tflow->tunnel_id = tunnel->tunnel_id;\n+\t\trte_atomic32_inc(&tunnel->refctn);\n+\t}\n \treturn idx;\n error:\n \tMLX5_ASSERT(flow);\n@@ -4657,6 +4968,13 @@ flow_list_destroy(struct rte_eth_dev *dev, uint32_t *list,\n \t\t}\n \t}\n \tmlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RTE_FLOW], flow_idx);\n+\tif (flow->tunnel) {\n+\t\tstruct mlx5_flow_tunnel *tunnel;\n+\t\ttunnel = mlx5_find_tunnel_id(dev, flow->tunnel_id);\n+\t\tRTE_VERIFY(tunnel);\n+\t\tif (rte_atomic32_dec_and_test(&tunnel->refctn))\n+\t\t\tmlx5_flow_tunnel_free(dev, tunnel);\n+\t}\n }\n \n /**\n@@ -6301,3 +6619,138 @@ mlx5_flow_get_aged_flows(struct rte_eth_dev *dev, void **contexts,\n \t\t dev->data->port_id);\n \treturn -ENOTSUP;\n }\n+\n+static void\n+mlx5_flow_tunnel_free(struct rte_eth_dev *dev,\n+\t\t      struct mlx5_flow_tunnel *tunnel)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_dev_ctx_shared *sh = priv->sh;\n+\tstruct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;\n+\tstruct mlx5_flow_id_pool *id_pool = thub->tunnel_ids;\n+\n+\tDRV_LOG(DEBUG, \"port %u release pmd tunnel id=0x%x\",\n+\t\tdev->data->port_id, tunnel->tunnel_id);\n+\tRTE_VERIFY(!rte_atomic32_read(&tunnel->refctn));\n+\tLIST_REMOVE(tunnel, chain);\n+\tmlx5_flow_id_release(id_pool, tunnel->tunnel_id);\n+\tfree(tunnel);\n+}\n+\n+static struct mlx5_flow_tunnel *\n+mlx5_find_tunnel_id(struct rte_eth_dev *dev, uint32_t id)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_dev_ctx_shared *sh = priv->sh;\n+\tstruct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;\n+\tstruct mlx5_flow_tunnel *tun;\n+\n+\tLIST_FOREACH(tun, &thub->tunnels, chain) {\n+\t\tif (tun->tunnel_id == id)\n+\t\t\tbreak;\n+\t}\n+\n+\treturn tun;\n+}\n+\n+static struct mlx5_flow_tunnel *\n+mlx5_flow_tunnel_allocate(struct rte_eth_dev *dev,\n+\t\t\t  const struct rte_flow_tunnel *app_tunnel)\n+{\n+\tint ret;\n+\tstruct mlx5_flow_tunnel *tunnel;\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_dev_ctx_shared *sh = priv->sh;\n+\tstruct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;\n+\tstruct mlx5_flow_id_pool *id_pool = thub->tunnel_ids;\n+\tuint32_t id;\n+\n+\tret = mlx5_flow_id_get(id_pool, &id);\n+\tif (ret)\n+\t\treturn NULL;\n+\t/**\n+\t * mlx5 flow tunnel is an auxlilary data structure\n+\t * It's not part of IO. No need to allocate it from\n+\t * huge pages pools dedicated for IO\n+\t */\n+\ttunnel = calloc(1, sizeof(*tunnel));\n+\tif (!tunnel) {\n+\t\tmlx5_flow_id_release(id_pool, id);\n+\t\treturn NULL;\n+\t}\n+\t/* initiate new PMD tunnel */\n+\tmemcpy(&tunnel->app_tunnel, app_tunnel, sizeof(*app_tunnel));\n+\trte_atomic32_init(&tunnel->refctn);\n+\ttunnel->tunnel_id = id;\n+\ttunnel->action.type = MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET;\n+\ttunnel->action.conf = tunnel;\n+\ttunnel->item.type = MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL;\n+\ttunnel->item.spec = tunnel;\n+\ttunnel->item.last = NULL;\n+\ttunnel->item.mask = NULL;\n+\tDRV_LOG(DEBUG, \"port %u new pmd tunnel id=0x%x\",\n+\t\tdev->data->port_id, tunnel->tunnel_id);\n+\n+\treturn tunnel;\n+}\n+\n+int\n+mlx5_get_flow_tunnel(struct rte_eth_dev *dev,\n+\t\t     const struct rte_flow_tunnel *app_tunnel,\n+\t\t     struct mlx5_flow_tunnel **tunnel)\n+{\n+\tint ret;\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_dev_ctx_shared *sh = priv->sh;\n+\tstruct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;\n+\tstruct mlx5_flow_tunnel *tun;\n+\n+\tLIST_FOREACH(tun, &thub->tunnels, chain) {\n+\t\tif (!memcmp(app_tunnel, &tun->app_tunnel,\n+\t\t\t    sizeof(*app_tunnel))) {\n+\t\t\t*tunnel = tun;\n+\t\t\tret = 0;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tif (!tun) {\n+\t\ttun = mlx5_flow_tunnel_allocate(dev, app_tunnel);\n+\t\tif (tun) {\n+\t\t\tLIST_INSERT_HEAD(&thub->tunnels, tun, chain);\n+\t\t\t*tunnel = tun;\n+\t\t} else {\n+\t\t\tret = -ENOMEM;\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n+void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh)\n+{\n+\tif (sh->tunnel_hub)\n+\t\treturn;\n+\tRTE_VERIFY(LIST_EMPTY(&sh->tunnel_hub->tunnels));\n+\tmlx5_flow_id_pool_release(sh->tunnel_hub->tunnel_ids);\n+\tfree(sh->tunnel_hub);\n+}\n+\n+int mlx5_alloc_tunnel_hub(struct mlx5_dev_ctx_shared *sh)\n+{\n+\tint err;\n+\n+\tsh->tunnel_hub = calloc(1, sizeof(*sh->tunnel_hub));\n+\tif (!sh->tunnel_hub)\n+\t\treturn -ENOMEM;\n+\tLIST_INIT(&sh->tunnel_hub->tunnels);\n+\tsh->tunnel_hub->tunnel_ids = mlx5_flow_id_pool_alloc(MLX5_MAX_TUNNELS);\n+\tif (!sh->tunnel_hub->tunnel_ids) {\n+\t\tfree(sh->tunnel_hub);\n+\t\terr = -rte_errno;\n+\t\tgoto out;\n+\t}\n+\terr = 0;\n+\n+out:\n+\treturn err;\n+}\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nindex 66caefce46..5d2be7d123 100644\n--- a/drivers/net/mlx5/mlx5_flow.h\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -26,6 +26,7 @@ enum mlx5_rte_flow_item_type {\n \tMLX5_RTE_FLOW_ITEM_TYPE_TAG,\n \tMLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE,\n \tMLX5_RTE_FLOW_ITEM_TYPE_VLAN,\n+\tMLX5_RTE_FLOW_ITEM_TYPE_TUNNEL,\n };\n \n /* Private (internal) rte flow actions. */\n@@ -35,6 +36,7 @@ enum mlx5_rte_flow_action_type {\n \tMLX5_RTE_FLOW_ACTION_TYPE_MARK,\n \tMLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG,\n \tMLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS,\n+\tMLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET,\n };\n \n /* Matches on selected register. */\n@@ -196,6 +198,7 @@ enum mlx5_feature_name {\n #define MLX5_FLOW_ACTION_SET_IPV6_DSCP (1ull << 33)\n #define MLX5_FLOW_ACTION_AGE (1ull << 34)\n #define MLX5_FLOW_ACTION_DEFAULT_MISS (1ull << 35)\n+#define MLX5_FLOW_ACTION_TUNNEL_TYPE1 (1ull << 36)\n \n #define MLX5_FLOW_FATE_ACTIONS \\\n \t(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \\\n@@ -816,6 +819,45 @@ struct mlx5_fdir_flow {\n \n #define HAIRPIN_FLOW_ID_BITS 28\n \n+#define MLX5_MAX_TUNNELS 63\n+#define MLX5_TUNNEL_MARK_MASK 0x3F0000u\n+#define TUNNEL_STEER_GROUP(grp) ((grp) | (1u << 31))\n+\n+struct mlx5_flow_tunnel {\n+\tLIST_ENTRY(mlx5_flow_tunnel) chain;\n+\tstruct rte_flow_tunnel app_tunnel;\t/** app tunnel copy */\n+\tuint32_t tunnel_id;\t\t/** unique tunnel ID */\n+\trte_atomic32_t refctn;\n+\tstruct rte_flow_action action;\n+\tstruct rte_flow_item item;\n+};\n+\n+/** PMD tunnel related context */\n+struct mlx5_flow_tunnel_hub {\n+\tLIST_HEAD(, mlx5_flow_tunnel) tunnels;\n+\tstruct mlx5_flow_id_pool *tunnel_ids;\n+};\n+\n+static inline bool\n+is_flow_tunnel_match_rule(__rte_unused struct rte_eth_dev *dev,\n+\t\t\t  __rte_unused const struct rte_flow_attr *attr,\n+\t\t\t  __rte_unused const struct rte_flow_item items[],\n+\t\t\t  __rte_unused const struct rte_flow_action actions[])\n+{\n+\treturn (items[0].type == (typeof(items[0].type))\n+\t\t\tMLX5_RTE_FLOW_ITEM_TYPE_TUNNEL);\n+}\n+\n+static inline bool\n+is_flow_tunnel_steer_rule(__rte_unused struct rte_eth_dev *dev,\n+\t\t\t  __rte_unused const struct rte_flow_attr *attr,\n+\t\t\t  __rte_unused const struct rte_flow_item items[],\n+\t\t\t  __rte_unused const struct rte_flow_action actions[])\n+{\n+\treturn (actions[0].type == (typeof(actions[0].type))\n+\t\t\tMLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET);\n+}\n+\n /* Flow structure. */\n struct rte_flow {\n \tILIST_ENTRY(uint32_t)next; /**< Index to the next flow structure. */\n@@ -823,12 +865,14 @@ struct rte_flow {\n \t/**< Device flow handles that are part of the flow. */\n \tuint32_t drv_type:2; /**< Driver type. */\n \tuint32_t fdir:1; /**< Identifier of associated FDIR if any. */\n+\tuint32_t tunnel:1;\n \tuint32_t hairpin_flow_id:HAIRPIN_FLOW_ID_BITS;\n \t/**< The flow id used for hairpin. */\n \tuint32_t copy_applied:1; /**< The MARK copy Flow os applied. */\n \tuint32_t rix_mreg_copy;\n \t/**< Index to metadata register copy table resource. */\n \tuint32_t counter; /**< Holds flow counter. */\n+\tuint32_t tunnel_id;  /**< Tunnel id */\n \tuint16_t meter; /**< Holds flow meter id. */\n } __rte_packed;\n \n@@ -1045,4 +1089,9 @@ int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,\n \t\t\t\t    const struct rte_flow_attr *attr);\n int mlx5_flow_meter_flush(struct rte_eth_dev *dev,\n \t\t\t  struct rte_mtr_error *error);\n+int mlx5_get_flow_tunnel(struct rte_eth_dev *dev,\n+\t\t\t const struct rte_flow_tunnel *app_tunnel,\n+\t\t\t struct mlx5_flow_tunnel **tunnel);\n+void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh);\n+int mlx5_alloc_tunnel_hub(struct mlx5_dev_ctx_shared *sh);\n #endif /* RTE_PMD_MLX5_FLOW_H_ */\ndiff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c\nindex 53399800ff..21af7fb93a 100644\n--- a/drivers/net/mlx5/mlx5_flow_dv.c\n+++ b/drivers/net/mlx5/mlx5_flow_dv.c\n@@ -3676,6 +3676,8 @@ flow_dv_validate_action_jump(const struct rte_flow_action *action,\n \t\t\t\t\t  NULL, \"action configuration not set\");\n \ttarget_group =\n \t\t((const struct rte_flow_action_jump *)action->conf)->group;\n+\tif (action_flags & MLX5_FLOW_ACTION_TUNNEL_TYPE1)\n+\t\ttarget_group = TUNNEL_STEER_GROUP(target_group);\n \tret = mlx5_flow_group_to_table(attributes, external, target_group,\n \t\t\t\t       true, &table, error);\n \tif (ret)\n@@ -5035,6 +5037,15 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,\n \t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ITEM,\n \t\t\t\t\t\t  NULL, \"item not supported\");\n \t\tswitch (type) {\n+\t\tcase MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL:\n+\t\t\tif (items[0].type != (typeof(items[0].type))\n+\t\t\t\t\t\tMLX5_RTE_FLOW_ITEM_TYPE_TUNNEL)\n+\t\t\t\treturn rte_flow_error_set\n+\t\t\t\t\t\t(error, EINVAL,\n+\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\tNULL, \"MLX5 private items \"\n+\t\t\t\t\t\t\"must be the first\");\n+\t\t\tbreak;\n \t\tcase RTE_FLOW_ITEM_TYPE_VOID:\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ITEM_TYPE_PORT_ID:\n@@ -5699,6 +5710,17 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,\n \t\t\taction_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;\n \t\t\trw_act_num += MLX5_ACT_NUM_SET_DSCP;\n \t\t\tbreak;\n+\t\tcase MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:\n+\t\t\tif (actions[0].type != (typeof(actions[0].type))\n+\t\t\t\tMLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET)\n+\t\t\t\treturn rte_flow_error_set\n+\t\t\t\t\t\t(error, EINVAL,\n+\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\tNULL, \"MLX5 private action \"\n+\t\t\t\t\t\t\"must be the first\");\n+\n+\t\t\taction_flags |= MLX5_FLOW_ACTION_TUNNEL_TYPE1;\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\treturn rte_flow_error_set(error, ENOTSUP,\n \t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n@@ -5706,6 +5728,31 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,\n \t\t\t\t\t\t  \"action not supported\");\n \t\t}\n \t}\n+\t/*\n+\t * Validate flow tunnel decap_set rule\n+\t */\n+\tif (action_flags & MLX5_FLOW_ACTION_TUNNEL_TYPE1) {\n+\t\tuint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP |\n+\t\t\t\t\t\tMLX5_FLOW_ACTION_MARK;\n+\n+\t\tif (action_flags & bad_actions_mask)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t\t(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, NULL,\n+\t\t\t\t\t\"Invalid RTE action in tunnel \"\n+\t\t\t\t\t\"set decap rule\");\n+\t\tif (!(action_flags & MLX5_FLOW_ACTION_JUMP))\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t\t(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, NULL,\n+\t\t\t\t\t\"tunnel set decap rule must terminate \"\n+\t\t\t\t\t\"with JUMP\");\n+\t\tif (!attr->ingress)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t\t(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, NULL,\n+\t\t\t\t\t\"tunnel flows for ingress traffic only\");\n+\t}\n \t/*\n \t * Validate the drop action mutual exclusion with other actions.\n \t * Drop action is mutually-exclusive with any other action, except for\n@@ -8110,11 +8157,14 @@ __flow_dv_translate(struct rte_eth_dev *dev,\n \tuint8_t next_protocol = 0xff;\n \tstruct rte_vlan_hdr vlan = { 0 };\n \tuint32_t table;\n+\tuint32_t attr_group;\n \tint ret = 0;\n \n+\tattr_group = !is_flow_tunnel_match_rule(dev, attr, items, actions) ?\n+\t\t\tattr->group : TUNNEL_STEER_GROUP(attr->group);\n \tmhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :\n \t\t\t\t\t   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;\n-\tret = mlx5_flow_group_to_table(attr, dev_flow->external, attr->group,\n+\tret = mlx5_flow_group_to_table(attr, dev_flow->external, attr_group,\n \t\t\t\t       !!priv->fdb_def_rule, &table, error);\n \tif (ret)\n \t\treturn ret;\n@@ -8125,6 +8175,15 @@ __flow_dv_translate(struct rte_eth_dev *dev,\n \t\tpriority = dev_conf->flow_prio - 1;\n \t/* number of actions must be set to 0 in case of dirty stack. */\n \tmhdr_res->actions_num = 0;\n+\tif (is_flow_tunnel_match_rule(dev, attr, items, actions)) {\n+\t\tif (flow_dv_create_action_l2_decap(dev, dev_flow,\n+\t\t\t\t\t\t   attr->transfer,\n+\t\t\t\t\t\t   error))\n+\t\t\treturn -rte_errno;\n+\t\tdev_flow->dv.actions[actions_n++] =\n+\t\t\t\tdev_flow->dv.encap_decap->action;\n+\t\taction_flags |= MLX5_FLOW_ACTION_DECAP;\n+\t}\n \tfor (; !actions_end ; actions++) {\n \t\tconst struct rte_flow_action_queue *queue;\n \t\tconst struct rte_flow_action_rss *rss;\n@@ -8134,6 +8193,7 @@ __flow_dv_translate(struct rte_eth_dev *dev,\n \t\tconst struct rte_flow_action_meter *mtr;\n \t\tstruct mlx5_flow_tbl_resource *tbl;\n \t\tuint32_t port_id = 0;\n+\t\tuint32_t jump_group;\n \t\tstruct mlx5_flow_dv_port_id_action_resource port_id_resource;\n \t\tint action_type = actions->type;\n \t\tconst struct rte_flow_action *found_action = NULL;\n@@ -8145,6 +8205,9 @@ __flow_dv_translate(struct rte_eth_dev *dev,\n \t\t\t\t\t\t  actions,\n \t\t\t\t\t\t  \"action not supported\");\n \t\tswitch (action_type) {\n+\t\tcase MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:\n+\t\t\taction_flags |= MLX5_FLOW_ACTION_TUNNEL_TYPE1;\n+\t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_VOID:\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_PORT_ID:\n@@ -8377,8 +8440,12 @@ __flow_dv_translate(struct rte_eth_dev *dev,\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_JUMP:\n \t\t\tjump_data = action->conf;\n+\t\t\tjump_group = !(action_flags &\n+\t\t\t\t\tMLX5_FLOW_ACTION_TUNNEL_TYPE1) ?\n+\t\t\t\t\tjump_data->group :\n+\t\t\t\t\tTUNNEL_STEER_GROUP(jump_data->group);\n \t\t\tret = mlx5_flow_group_to_table(attr, dev_flow->external,\n-\t\t\t\t\t\t       jump_data->group,\n+\t\t\t\t\t\t       jump_group,\n \t\t\t\t\t\t       !!priv->fdb_def_rule,\n \t\t\t\t\t\t       &table, error);\n \t\t\tif (ret)\n",
    "prefixes": [
        "v2",
        "3/4"
    ]
}