get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 117003,
    "url": "http://patches.dpdk.org/api/patches/117003/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20220928033130.9106-5-suanmingm@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": "<20220928033130.9106-5-suanmingm@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20220928033130.9106-5-suanmingm@nvidia.com",
    "date": "2022-09-28T03:31:17",
    "name": "[v2,04/17] net/mlx5: add modify field hws support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "1310b9791613a4a57e378de7b6cbfc172726faf4",
    "submitter": {
        "id": 1887,
        "url": "http://patches.dpdk.org/api/people/1887/?format=api",
        "name": "Suanming Mou",
        "email": "suanmingm@nvidia.com"
    },
    "delegate": {
        "id": 3268,
        "url": "http://patches.dpdk.org/api/users/3268/?format=api",
        "username": "rasland",
        "first_name": "Raslan",
        "last_name": "Darawsheh",
        "email": "rasland@nvidia.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20220928033130.9106-5-suanmingm@nvidia.com/mbox/",
    "series": [
        {
            "id": 24870,
            "url": "http://patches.dpdk.org/api/series/24870/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=24870",
            "date": "2022-09-28T03:31:15",
            "name": "net/mlx5: HW steering PMD update",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/24870/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/117003/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/117003/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 A92E4A00C2;\n\tWed, 28 Sep 2022 05:32:35 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id DBC9B42B77;\n\tWed, 28 Sep 2022 05:32:12 +0200 (CEST)",
            "from NAM04-MW2-obe.outbound.protection.outlook.com\n (mail-mw2nam04on2050.outbound.protection.outlook.com [40.107.101.50])\n by mails.dpdk.org (Postfix) with ESMTP id CB14E427F5\n for <dev@dpdk.org>; Wed, 28 Sep 2022 05:32:08 +0200 (CEST)",
            "from DS7PR05CA0087.namprd05.prod.outlook.com (2603:10b6:8:56::9) by\n DM4PR12MB5358.namprd12.prod.outlook.com (2603:10b6:5:39c::21) with\n Microsoft\n SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.5676.15; Wed, 28 Sep 2022 03:32:06 +0000",
            "from DM6NAM11FT098.eop-nam11.prod.protection.outlook.com\n (2603:10b6:8:56:cafe::2d) by DS7PR05CA0087.outlook.office365.com\n (2603:10b6:8:56::9) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.15 via Frontend\n Transport; Wed, 28 Sep 2022 03:32:06 +0000",
            "from mail.nvidia.com (216.228.117.161) by\n DM6NAM11FT098.mail.protection.outlook.com (10.13.173.61) with Microsoft SMTP\n Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.5676.17 via Frontend Transport; Wed, 28 Sep 2022 03:32:06 +0000",
            "from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com\n (10.129.200.67) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Tue, 27 Sep\n 2022 20:31:56 -0700",
            "from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com\n (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Tue, 27 Sep\n 2022 20:31:54 -0700"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=CnRM4DENUpJP4PR2j5VAjXmyaf05UF3udSWWdliiZeW1i+ZBsagIxMLRwLd0nQ4XVE9U9uUZj3Q2m7IEOUVyxoPgDszxVsN/aY77gb7py/WUfyOL7y81P6QnBdYkp48HHln+iebD219Qw58C9475/htTY6VpKWcsLFVpG56Ig2n5EUmk2OhMWclA12Qvd/D+igeILaQ+PLMiRTarRveXtAgTsSfXkU3Qtd7JdCA7K8ZYqcwpY8agyxO8sB+0UecOLJGBe7WUYy0EExS1114SzwhHYnd+qUT0+THH+ccvOagPYX9vuMcWKIo69IBP+Etz25MB4kMMZ0NCNLkC3igj6Q==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector9901;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=8qJD28GXa4bAWjNqfKOG1LqDkDIMjmJsNiU1xKcXSPo=;\n b=L53hHeMLv0Me3AxWISJoJzYLa2IVsiBhoaR+Xnl1NiTyUMAMN02oZNfRzKBpIGw1rZU/yAzJrL1uHzsbwb1GWccJD350SMx9CHEnL144ApPoWBQ8kjV9+lO2ZiY0wyFxaZDXhbHM8jrBUer59i8A1GvAlY72E4M1OukJSy+IxEysdk0UN+klJlIw/lDPjnPYs/CbeFuXNGiFS4WUR59wvBZhH1RLfQPUCjHOIjFDO7xoWNUsrLzQ2SJA/sE5CL7Z0us3Y7720WhWtqJWNh+vFbn9+BmcN3BUXJLedEiaSefRfnWGfwVAC6+vqLsvJQrlfGmmKoLnwmqJHQercY+6yg==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass (sender ip is\n 216.228.117.161) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com;\n dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com;\n dkim=none (message not signed); arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com;\n s=selector2;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=8qJD28GXa4bAWjNqfKOG1LqDkDIMjmJsNiU1xKcXSPo=;\n b=lcGGG7qj464isAbBzeXwsBacj5FEFXtxtVTjkqq4wdSwS1Gt6IH0Vqpe0jhA9MgUepl3Wrg9l3sWiUcmTthQJV36L+P0JrexiImfYIjCukDqdTUok3zWEkYU6yeCxZ15OG/BgYV8qAadEQ5XY/SUPBGH3qEJXcF/rfRxgV2KhoXxw4crp90S91oI/mbPAWmrbwfsamzgeRGVeDOWGp//7W2A0BfSYBrokA/ENAQIGLewHn8T1LiBoCIjbfr/47vV9dkpe23Y9y4w8bMpNNi21MC4+oF95czMI8PG+PbfaAjBVkRU1fLdntCfvf0lz0R5wtngM4gyV6mNYGvqKD/y8w==",
        "X-MS-Exchange-Authentication-Results": "spf=pass (sender IP is 216.228.117.161)\n smtp.mailfrom=nvidia.com;\n dkim=none (message not signed)\n header.d=none;dmarc=pass action=none header.from=nvidia.com;",
        "Received-SPF": "Pass (protection.outlook.com: domain of nvidia.com designates\n 216.228.117.161 as permitted sender) receiver=protection.outlook.com;\n client-ip=216.228.117.161; helo=mail.nvidia.com; pr=C",
        "From": "Suanming Mou <suanmingm@nvidia.com>",
        "To": "Matan Azrad <matan@nvidia.com>, Viacheslav Ovsiienko\n <viacheslavo@nvidia.com>",
        "CC": "<dev@dpdk.org>, <rasland@nvidia.com>, <orika@nvidia.com>, \"Dariusz\n Sosnowski\" <dsosnowski@nvidia.com>",
        "Subject": "[PATCH v2 04/17] net/mlx5: add modify field hws support",
        "Date": "Wed, 28 Sep 2022 06:31:17 +0300",
        "Message-ID": "<20220928033130.9106-5-suanmingm@nvidia.com>",
        "X-Mailer": "git-send-email 2.18.1",
        "In-Reply-To": "<20220928033130.9106-1-suanmingm@nvidia.com>",
        "References": "<20220923144334.27736-1-suanmingm@nvidia.com>\n <20220928033130.9106-1-suanmingm@nvidia.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.126.230.35]",
        "X-ClientProxiedBy": "rnnvmail201.nvidia.com (10.129.68.8) To\n rnnvmail201.nvidia.com (10.129.68.8)",
        "X-EOPAttributedMessage": "0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "DM6NAM11FT098:EE_|DM4PR12MB5358:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "8c28dc64-2979-4327-c1b2-08daa102046a",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n gG+Mb7mkbqcbjcsPzhw32x3GiinSw1Zl2wfmLDAwPGXqUC1tnQ3Q2HT89QB1/iQ1vg+ROA5fKNEAkl6KhlrCKDV8DI8e3TykbQ7C0bgsBKqU6vaxiBYinWTINu7Amqv3GqNQpUJGCt3glFffR1mXzFcck2lPbtIijFz9jfhaYyQ4kCPxM+dKiEubWNR0TWVstG/s7ZYofxm+MKxpnOqzcRZndfOie5eqW1w/8sBcNh6NG1f9vcOrCY2kgm01wywZahq2jkaaWfaKScjP+MLg5BWgJPmVuZ1x7P2+X8EEsSka/FdfPyjYeupsOO2sZoUU4Kb6l9JDDgIOSC22KM6FZb4fW7n2CbSRRSk5duPd7NyOwbB3hrFlfO6V5SORUnYvEVfU66nIwDjC/wmL5CwzoB0bDcOaQzE/8z5hk+vDJfet3eYMwyM/9weBfzO/3ruqk25j3BgfxIJBTCpibq0KHPFEIBXwmPH/DtVQS1TAhutsBU2HNIu61GvHF2IPlrZDNWYFcqVhNaWylBVDFeiMAs0/H+QbsLUlXiMUpnc1mqNEvEZd1Nlt/r3DE/rPzSvu2kFlP+EOJMjthaHtyD9gQybIAmZMvWmdlO50Q+uvtdL5qdGQJfxJUzXh9U9T29eIgp+VWx7wCRMJLram8gvg1pu8GVq28cfB80kLimhdP5wSAmEOh4J9H3wVLFbnZRlke9wXBrvHCoIPH+4nFtdCOm/aFd7AspjjWgqUY/Cks3W8cV/QaaBAVQpEWiQ7QVDep2XbnxKufV8QmImm6x/t8g==",
        "X-Forefront-Antispam-Report": "CIP:216.228.117.161; CTRY:US; LANG:en; SCL:1;\n SRV:;\n IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge2.nvidia.com; CAT:NONE;\n SFS:(13230022)(4636009)(346002)(39860400002)(376002)(396003)(136003)(451199015)(36840700001)(46966006)(40470700004)(16526019)(47076005)(83380400001)(36860700001)(426003)(186003)(336012)(1076003)(55016003)(40480700001)(4326008)(8676002)(41300700001)(70586007)(70206006)(86362001)(356005)(6666004)(5660300002)(316002)(54906003)(107886003)(8936002)(2616005)(110136005)(36756003)(26005)(6286002)(6636002)(7696005)(30864003)(478600001)(82740400003)(40460700003)(82310400005)(7636003)(2906002)(579004)(559001);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "Nvidia.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "28 Sep 2022 03:32:06.0895 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 8c28dc64-2979-4327-c1b2-08daa102046a",
        "X-MS-Exchange-CrossTenant-Id": "43083d15-7273-40c1-b7db-39efd9ccc17a",
        "X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp": "\n TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.161];\n Helo=[mail.nvidia.com]",
        "X-MS-Exchange-CrossTenant-AuthSource": "\n DM6NAM11FT098.eop-nam11.prod.protection.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DM4PR12MB5358",
        "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"
    },
    "content": "This patch introduces support for modify_field rte_flow actions in HWS\nmode. Support includes:\n\n- Ingress and egress domains,\n\t- SET and ADD operations,\n\t- usage of arbitrary bit offsets and widths for packet and metadata\n\tfields.\n\n\tSupport is implemented in two phases:\n\n\t1. On flow table creation the hardware commands are generated, based\n\ton rte_flow action templates, and stored alongside action template.\n\t2. On flow rule creation/queueing the hardware commands are updated with\n\tvalues provided by the user. Any masks over immediate values, provided\n\tin action templates, are applied to these values before enqueueing rules\n\tfor creation.\n\nSigned-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>\nSigned-off-by: Suanming Mou <suanmingm@nvidia.com>\n---\n drivers/common/mlx5/mlx5_prm.h   |   2 +\n drivers/net/mlx5/linux/mlx5_os.c |  18 +-\n drivers/net/mlx5/mlx5.h          |   1 +\n drivers/net/mlx5/mlx5_flow.h     |  96 +++++\n drivers/net/mlx5/mlx5_flow_dv.c  | 551 ++++++++++++++--------------\n drivers/net/mlx5/mlx5_flow_hw.c  | 595 ++++++++++++++++++++++++++++++-\n 6 files changed, 988 insertions(+), 275 deletions(-)",
    "diff": "diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h\nindex f832bd77cb..c82ec94465 100644\n--- a/drivers/common/mlx5/mlx5_prm.h\n+++ b/drivers/common/mlx5/mlx5_prm.h\n@@ -746,6 +746,8 @@ enum mlx5_modification_field {\n \tMLX5_MODI_IN_TCP_ACK_NUM = 0x5C,\n \tMLX5_MODI_GTP_TEID = 0x6E,\n \tMLX5_MODI_OUT_IP_ECN = 0x73,\n+\tMLX5_MODI_TUNNEL_HDR_DW_1 = 0x75,\n+\tMLX5_MODI_GTPU_FIRST_EXT_DW_0 = 0x76,\n };\n \n /* Total number of metadata reg_c's. */\ndiff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c\nindex aed55e6a62..b7cc11a2ef 100644\n--- a/drivers/net/mlx5/linux/mlx5_os.c\n+++ b/drivers/net/mlx5/linux/mlx5_os.c\n@@ -1540,6 +1540,15 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,\n \t\t\t\t       mlx5_hrxq_clone_free_cb);\n \tif (!priv->hrxqs)\n \t\tgoto error;\n+\tmlx5_set_metadata_mask(eth_dev);\n+\tif (sh->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&\n+\t    !priv->sh->dv_regc0_mask) {\n+\t\tDRV_LOG(ERR, \"metadata mode %u is not supported \"\n+\t\t\t     \"(no metadata reg_c[0] is available)\",\n+\t\t\t     sh->config.dv_xmeta_en);\n+\t\t\terr = ENOTSUP;\n+\t\t\tgoto error;\n+\t}\n \trte_rwlock_init(&priv->ind_tbls_lock);\n \tif (priv->sh->config.dv_flow_en == 2) {\n #ifdef HAVE_IBV_FLOW_DV_SUPPORT\n@@ -1566,15 +1575,6 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,\n \t\terr = -err;\n \t\tgoto error;\n \t}\n-\tmlx5_set_metadata_mask(eth_dev);\n-\tif (sh->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&\n-\t    !priv->sh->dv_regc0_mask) {\n-\t\tDRV_LOG(ERR, \"metadata mode %u is not supported \"\n-\t\t\t     \"(no metadata reg_c[0] is available)\",\n-\t\t\t     sh->config.dv_xmeta_en);\n-\t\t\terr = ENOTSUP;\n-\t\t\tgoto error;\n-\t}\n \t/* Query availability of metadata reg_c's. */\n \tif (!priv->sh->metadata_regc_check_flag) {\n \t\terr = mlx5_flow_discover_mreg_c(eth_dev);\ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex e855dc6ab5..a93af75baa 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -343,6 +343,7 @@ struct mlx5_hw_q_job {\n \tstruct rte_flow_hw *flow; /* Flow attached to the job. */\n \tvoid *user_data; /* Job user data. */\n \tuint8_t *encap_data; /* Encap data. */\n+\tstruct mlx5_modification_cmd *mhdr_cmd;\n };\n \n /* HW steering job descriptor LIFO pool. */\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nindex 1c9f5fc1d5..0eab3a3797 100644\n--- a/drivers/net/mlx5/mlx5_flow.h\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -1007,6 +1007,51 @@ flow_items_to_tunnel(const struct rte_flow_item items[])\n \treturn items[0].spec;\n }\n \n+/**\n+ * Fetch 1, 2, 3 or 4 byte field from the byte array\n+ * and return as unsigned integer in host-endian format.\n+ *\n+ * @param[in] data\n+ *   Pointer to data array.\n+ * @param[in] size\n+ *   Size of field to extract.\n+ *\n+ * @return\n+ *   converted field in host endian format.\n+ */\n+static inline uint32_t\n+flow_dv_fetch_field(const uint8_t *data, uint32_t size)\n+{\n+\tuint32_t ret;\n+\n+\tswitch (size) {\n+\tcase 1:\n+\t\tret = *data;\n+\t\tbreak;\n+\tcase 2:\n+\t\tret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);\n+\t\tbreak;\n+\tcase 3:\n+\t\tret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);\n+\t\tret = (ret << 8) | *(data + sizeof(uint16_t));\n+\t\tbreak;\n+\tcase 4:\n+\t\tret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data);\n+\t\tbreak;\n+\tdefault:\n+\t\tMLX5_ASSERT(false);\n+\t\tret = 0;\n+\t\tbreak;\n+\t}\n+\treturn ret;\n+}\n+\n+struct field_modify_info {\n+\tuint32_t size; /* Size of field in protocol header, in bytes. */\n+\tuint32_t offset; /* Offset of field in protocol header, in bytes. */\n+\tenum mlx5_modification_field id;\n+};\n+\n /* HW steering flow attributes. */\n struct mlx5_flow_attr {\n \tuint32_t port_id; /* Port index. */\n@@ -1067,6 +1112,29 @@ struct mlx5_action_construct_data {\n \t\t\t/* encap data len. */\n \t\t\tuint16_t len;\n \t\t} encap;\n+\t\tstruct {\n+\t\t\t/* Modify header action offset in pattern. */\n+\t\t\tuint16_t mhdr_cmds_off;\n+\t\t\t/* Offset in pattern after modify header actions. */\n+\t\t\tuint16_t mhdr_cmds_end;\n+\t\t\t/*\n+\t\t\t * True if this action is masked and does not need to\n+\t\t\t * be generated.\n+\t\t\t */\n+\t\t\tbool shared;\n+\t\t\t/*\n+\t\t\t * Modified field definitions in dst field (SET, ADD)\n+\t\t\t * or src field (COPY).\n+\t\t\t */\n+\t\t\tstruct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS];\n+\t\t\t/* Modified field definitions in dst field (COPY). */\n+\t\t\tstruct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS];\n+\t\t\t/*\n+\t\t\t * Masks applied to field values to generate\n+\t\t\t * PRM actions.\n+\t\t\t */\n+\t\t\tuint32_t mask[MLX5_ACT_MAX_MOD_FIELDS];\n+\t\t} modify_header;\n \t\tstruct {\n \t\t\tuint64_t types; /* RSS hash types. */\n \t\t\tuint32_t level; /* RSS level. */\n@@ -1092,6 +1160,7 @@ struct rte_flow_actions_template {\n \tstruct rte_flow_actions_template_attr attr;\n \tstruct rte_flow_action *actions; /* Cached flow actions. */\n \tstruct rte_flow_action *masks; /* Cached action masks.*/\n+\tuint16_t mhdr_off; /* Offset of DR modify header action. */\n \tuint32_t refcnt; /* Reference counter. */\n };\n \n@@ -1112,6 +1181,22 @@ struct mlx5_hw_encap_decap_action {\n \tuint8_t data[]; /* Action data. */\n };\n \n+#define MLX5_MHDR_MAX_CMD ((MLX5_MAX_MODIFY_NUM) * 2 + 1)\n+\n+/* Modify field action struct. */\n+struct mlx5_hw_modify_header_action {\n+\t/* Reference to DR action */\n+\tstruct mlx5dr_action *action;\n+\t/* Modify header action position in action rule table. */\n+\tuint16_t pos;\n+\t/* Is MODIFY_HEADER action shared across flows in table. */\n+\tbool shared;\n+\t/* Amount of modification commands stored in the precompiled buffer. */\n+\tuint32_t mhdr_cmds_num;\n+\t/* Precompiled modification commands. */\n+\tstruct mlx5_modification_cmd mhdr_cmds[MLX5_MHDR_MAX_CMD];\n+};\n+\n /* The maximum actions support in the flow. */\n #define MLX5_HW_MAX_ACTS 16\n \n@@ -1121,6 +1206,7 @@ struct mlx5_hw_actions {\n \tLIST_HEAD(act_list, mlx5_action_construct_data) act_list;\n \tstruct mlx5_hw_jump_action *jump; /* Jump action. */\n \tstruct mlx5_hrxq *tir; /* TIR action. */\n+\tstruct mlx5_hw_modify_header_action *mhdr; /* Modify header action. */\n \t/* Encap/Decap action. */\n \tstruct mlx5_hw_encap_decap_action *encap_decap;\n \tuint16_t encap_decap_pos; /* Encap/Decap action position. */\n@@ -2201,6 +2287,16 @@ int flow_dv_action_query(struct rte_eth_dev *dev,\n size_t flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type);\n int flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf,\n \t\t\t   size_t *size, struct rte_flow_error *error);\n+void mlx5_flow_field_id_to_modify_info\n+\t\t(const struct rte_flow_action_modify_data *data,\n+\t\t struct field_modify_info *info, uint32_t *mask,\n+\t\t uint32_t width, struct rte_eth_dev *dev,\n+\t\t const struct rte_flow_attr *attr, struct rte_flow_error *error);\n+int flow_dv_convert_modify_action(struct rte_flow_item *item,\n+\t\t\t      struct field_modify_info *field,\n+\t\t\t      struct field_modify_info *dcopy,\n+\t\t\t      struct mlx5_flow_dv_modify_hdr_resource *resource,\n+\t\t\t      uint32_t type, struct rte_flow_error *error);\n \n #define MLX5_PF_VPORT_ID 0\n #define MLX5_ECPF_VPORT_ID 0xFFFE\ndiff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c\nindex a9b0e84736..e4af9d910b 100644\n--- a/drivers/net/mlx5/mlx5_flow_dv.c\n+++ b/drivers/net/mlx5/mlx5_flow_dv.c\n@@ -241,12 +241,6 @@ rte_col_2_mlx5_col(enum rte_color rcol)\n \treturn MLX5_FLOW_COLOR_UNDEFINED;\n }\n \n-struct field_modify_info {\n-\tuint32_t size; /* Size of field in protocol header, in bytes. */\n-\tuint32_t offset; /* Offset of field in protocol header, in bytes. */\n-\tenum mlx5_modification_field id;\n-};\n-\n struct field_modify_info modify_eth[] = {\n \t{4,  0, MLX5_MODI_OUT_DMAC_47_16},\n \t{2,  4, MLX5_MODI_OUT_DMAC_15_0},\n@@ -379,45 +373,6 @@ mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action,\n \t}\n }\n \n-/**\n- * Fetch 1, 2, 3 or 4 byte field from the byte array\n- * and return as unsigned integer in host-endian format.\n- *\n- * @param[in] data\n- *   Pointer to data array.\n- * @param[in] size\n- *   Size of field to extract.\n- *\n- * @return\n- *   converted field in host endian format.\n- */\n-static inline uint32_t\n-flow_dv_fetch_field(const uint8_t *data, uint32_t size)\n-{\n-\tuint32_t ret;\n-\n-\tswitch (size) {\n-\tcase 1:\n-\t\tret = *data;\n-\t\tbreak;\n-\tcase 2:\n-\t\tret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);\n-\t\tbreak;\n-\tcase 3:\n-\t\tret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);\n-\t\tret = (ret << 8) | *(data + sizeof(uint16_t));\n-\t\tbreak;\n-\tcase 4:\n-\t\tret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data);\n-\t\tbreak;\n-\tdefault:\n-\t\tMLX5_ASSERT(false);\n-\t\tret = 0;\n-\t\tbreak;\n-\t}\n-\treturn ret;\n-}\n-\n /**\n  * Convert modify-header action to DV specification.\n  *\n@@ -446,7 +401,7 @@ flow_dv_fetch_field(const uint8_t *data, uint32_t size)\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n flow_dv_convert_modify_action(struct rte_flow_item *item,\n \t\t\t      struct field_modify_info *field,\n \t\t\t      struct field_modify_info *dcopy,\n@@ -1464,7 +1419,32 @@ mlx5_flow_item_field_width(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n-static void\n+static __rte_always_inline uint8_t\n+flow_modify_info_mask_8(uint32_t length, uint32_t off)\n+{\n+\treturn (0xffu >> (8 - length)) << off;\n+}\n+\n+static __rte_always_inline uint16_t\n+flow_modify_info_mask_16(uint32_t length, uint32_t off)\n+{\n+\treturn rte_cpu_to_be_16((0xffffu >> (16 - length)) << off);\n+}\n+\n+static __rte_always_inline uint32_t\n+flow_modify_info_mask_32(uint32_t length, uint32_t off)\n+{\n+\treturn rte_cpu_to_be_32((0xffffffffu >> (32 - length)) << off);\n+}\n+\n+static __rte_always_inline uint32_t\n+flow_modify_info_mask_32_masked(uint32_t length, uint32_t off, uint32_t post_mask)\n+{\n+\tuint32_t mask = (0xffffffffu >> (32 - length)) << off;\n+\treturn rte_cpu_to_be_32(mask & post_mask);\n+}\n+\n+void\n mlx5_flow_field_id_to_modify_info\n \t\t(const struct rte_flow_action_modify_data *data,\n \t\t struct field_modify_info *info, uint32_t *mask,\n@@ -1473,323 +1453,340 @@ mlx5_flow_field_id_to_modify_info\n {\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n \tuint32_t idx = 0;\n-\tuint32_t off = 0;\n-\n-\tswitch (data->field) {\n+\tuint32_t off_be = 0;\n+\tuint32_t length = 0;\n+\tswitch ((int)data->field) {\n \tcase RTE_FLOW_FIELD_START:\n \t\t/* not supported yet */\n \t\tMLX5_ASSERT(false);\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_MAC_DST:\n-\t\toff = data->offset > 16 ? data->offset - 16 : 0;\n-\t\tif (mask) {\n-\t\t\tif (data->offset < 16) {\n-\t\t\t\tinfo[idx] = (struct field_modify_info){2, 4,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DMAC_15_0};\n-\t\t\t\tif (width < 16) {\n-\t\t\t\t\tmask[1] = rte_cpu_to_be_16(0xffff >>\n-\t\t\t\t\t\t\t\t (16 - width));\n-\t\t\t\t\twidth = 0;\n-\t\t\t\t} else {\n-\t\t\t\t\tmask[1] = RTE_BE16(0xffff);\n-\t\t\t\t\twidth -= 16;\n-\t\t\t\t}\n-\t\t\t\tif (!width)\n-\t\t\t\t\tbreak;\n-\t\t\t\t++idx;\n-\t\t\t}\n-\t\t\tinfo[idx] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DMAC_47_16};\n-\t\t\tmask[0] = rte_cpu_to_be_32((0xffffffff >>\n-\t\t\t\t\t\t    (32 - width)) << off);\n+\t\tMLX5_ASSERT(data->offset + width <= 48);\n+\t\toff_be = 48 - (data->offset + width);\n+\t\tif (off_be < 16) {\n+\t\t\tinfo[idx] = (struct field_modify_info){2, 4,\n+\t\t\t\t\tMLX5_MODI_OUT_DMAC_15_0};\n+\t\t\tlength = off_be + width <= 16 ? width : 16 - off_be;\n+\t\t\tif (mask)\n+\t\t\t\tmask[1] = flow_modify_info_mask_16(length,\n+\t\t\t\t\t\t\t\t   off_be);\n+\t\t\telse\n+\t\t\t\tinfo[idx].offset = off_be;\n+\t\t\twidth -= length;\n+\t\t\tif (!width)\n+\t\t\t\tbreak;\n+\t\t\toff_be = 0;\n+\t\t\tidx++;\n \t\t} else {\n-\t\t\tif (data->offset < 16)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){2, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DMAC_15_0};\n-\t\t\tinfo[idx] = (struct field_modify_info){4, off,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DMAC_47_16};\n+\t\t\toff_be -= 16;\n \t\t}\n+\t\tinfo[idx] = (struct field_modify_info){4, 0,\n+\t\t\t\tMLX5_MODI_OUT_DMAC_47_16};\n+\t\tif (mask)\n+\t\t\tmask[0] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_MAC_SRC:\n-\t\toff = data->offset > 16 ? data->offset - 16 : 0;\n-\t\tif (mask) {\n-\t\t\tif (data->offset < 16) {\n-\t\t\t\tinfo[idx] = (struct field_modify_info){2, 4,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SMAC_15_0};\n-\t\t\t\tif (width < 16) {\n-\t\t\t\t\tmask[1] = rte_cpu_to_be_16(0xffff >>\n-\t\t\t\t\t\t\t\t (16 - width));\n-\t\t\t\t\twidth = 0;\n-\t\t\t\t} else {\n-\t\t\t\t\tmask[1] = RTE_BE16(0xffff);\n-\t\t\t\t\twidth -= 16;\n-\t\t\t\t}\n-\t\t\t\tif (!width)\n-\t\t\t\t\tbreak;\n-\t\t\t\t++idx;\n-\t\t\t}\n-\t\t\tinfo[idx] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SMAC_47_16};\n-\t\t\tmask[0] = rte_cpu_to_be_32((0xffffffff >>\n-\t\t\t\t\t\t    (32 - width)) << off);\n+\t\tMLX5_ASSERT(data->offset + width <= 48);\n+\t\toff_be = 48 - (data->offset + width);\n+\t\tif (off_be < 16) {\n+\t\t\tinfo[idx] = (struct field_modify_info){2, 4,\n+\t\t\t\t\tMLX5_MODI_OUT_SMAC_15_0};\n+\t\t\tlength = off_be + width <= 16 ? width : 16 - off_be;\n+\t\t\tif (mask)\n+\t\t\t\tmask[1] = flow_modify_info_mask_16(length,\n+\t\t\t\t\t\t\t\t   off_be);\n+\t\t\telse\n+\t\t\t\tinfo[idx].offset = off_be;\n+\t\t\twidth -= length;\n+\t\t\tif (!width)\n+\t\t\t\tbreak;\n+\t\t\toff_be = 0;\n+\t\t\tidx++;\n \t\t} else {\n-\t\t\tif (data->offset < 16)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){2, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SMAC_15_0};\n-\t\t\tinfo[idx] = (struct field_modify_info){4, off,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SMAC_47_16};\n+\t\t\toff_be -= 16;\n \t\t}\n+\t\tinfo[idx] = (struct field_modify_info){4, 0,\n+\t\t\t\tMLX5_MODI_OUT_SMAC_47_16};\n+\t\tif (mask)\n+\t\t\tmask[0] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_VLAN_TYPE:\n \t\t/* not supported yet */\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_VLAN_ID:\n+\t\tMLX5_ASSERT(data->offset + width <= 12);\n+\t\toff_be = 12 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){2, 0,\n \t\t\t\t\tMLX5_MODI_OUT_FIRST_VID};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_16(0x0fff >> (12 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_16(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_MAC_TYPE:\n+\t\tMLX5_ASSERT(data->offset + width <= 16);\n+\t\toff_be = 16 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){2, 0,\n \t\t\t\t\tMLX5_MODI_OUT_ETHERTYPE};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_16(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_IPV4_DSCP:\n+\t\tMLX5_ASSERT(data->offset + width <= 6);\n+\t\toff_be = 6 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){1, 0,\n \t\t\t\t\tMLX5_MODI_OUT_IP_DSCP};\n \t\tif (mask)\n-\t\t\tmask[idx] = 0x3f >> (6 - width);\n+\t\t\tmask[idx] = flow_modify_info_mask_8(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_IPV4_TTL:\n+\t\tMLX5_ASSERT(data->offset + width <= 8);\n+\t\toff_be = 8 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){1, 0,\n \t\t\t\t\tMLX5_MODI_OUT_IPV4_TTL};\n \t\tif (mask)\n-\t\t\tmask[idx] = 0xff >> (8 - width);\n+\t\t\tmask[idx] = flow_modify_info_mask_8(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_IPV4_SRC:\n+\t\tMLX5_ASSERT(data->offset + width <= 32);\n+\t\toff_be = 32 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){4, 0,\n \t\t\t\t\tMLX5_MODI_OUT_SIPV4};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t     (32 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_IPV4_DST:\n+\t\tMLX5_ASSERT(data->offset + width <= 32);\n+\t\toff_be = 32 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){4, 0,\n \t\t\t\t\tMLX5_MODI_OUT_DIPV4};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t     (32 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_IPV6_DSCP:\n+\t\tMLX5_ASSERT(data->offset + width <= 6);\n+\t\toff_be = 6 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){1, 0,\n \t\t\t\t\tMLX5_MODI_OUT_IP_DSCP};\n \t\tif (mask)\n-\t\t\tmask[idx] = 0x3f >> (6 - width);\n+\t\t\tmask[idx] = flow_modify_info_mask_8(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_IPV6_HOPLIMIT:\n+\t\tMLX5_ASSERT(data->offset + width <= 8);\n+\t\toff_be = 8 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){1, 0,\n \t\t\t\t\tMLX5_MODI_OUT_IPV6_HOPLIMIT};\n \t\tif (mask)\n-\t\t\tmask[idx] = 0xff >> (8 - width);\n+\t\t\tmask[idx] = flow_modify_info_mask_8(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n-\tcase RTE_FLOW_FIELD_IPV6_SRC:\n-\t\tif (mask) {\n-\t\t\tif (data->offset < 32) {\n-\t\t\t\tinfo[idx] = (struct field_modify_info){4, 12,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SIPV6_31_0};\n-\t\t\t\tif (width < 32) {\n-\t\t\t\t\tmask[3] =\n-\t\t\t\t\t\trte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t\t\t (32 - width));\n-\t\t\t\t\twidth = 0;\n-\t\t\t\t} else {\n-\t\t\t\t\tmask[3] = RTE_BE32(0xffffffff);\n-\t\t\t\t\twidth -= 32;\n-\t\t\t\t}\n-\t\t\t\tif (!width)\n-\t\t\t\t\tbreak;\n-\t\t\t\t++idx;\n-\t\t\t}\n-\t\t\tif (data->offset < 64) {\n-\t\t\t\tinfo[idx] = (struct field_modify_info){4, 8,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SIPV6_63_32};\n-\t\t\t\tif (width < 32) {\n-\t\t\t\t\tmask[2] =\n-\t\t\t\t\t\trte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t\t\t (32 - width));\n-\t\t\t\t\twidth = 0;\n-\t\t\t\t} else {\n-\t\t\t\t\tmask[2] = RTE_BE32(0xffffffff);\n-\t\t\t\t\twidth -= 32;\n-\t\t\t\t}\n-\t\t\t\tif (!width)\n-\t\t\t\t\tbreak;\n-\t\t\t\t++idx;\n-\t\t\t}\n-\t\t\tif (data->offset < 96) {\n-\t\t\t\tinfo[idx] = (struct field_modify_info){4, 4,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SIPV6_95_64};\n-\t\t\t\tif (width < 32) {\n-\t\t\t\t\tmask[1] =\n-\t\t\t\t\t\trte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t\t\t (32 - width));\n-\t\t\t\t\twidth = 0;\n-\t\t\t\t} else {\n-\t\t\t\t\tmask[1] = RTE_BE32(0xffffffff);\n-\t\t\t\t\twidth -= 32;\n-\t\t\t\t}\n-\t\t\t\tif (!width)\n-\t\t\t\t\tbreak;\n-\t\t\t\t++idx;\n+\tcase RTE_FLOW_FIELD_IPV6_SRC: {\n+\t\t/*\n+\t\t * Fields corresponding to IPv6 source address bytes\n+\t\t * arranged according to network byte ordering.\n+\t\t */\n+\t\tstruct field_modify_info fields[] = {\n+\t\t\t{ 4, 0, MLX5_MODI_OUT_SIPV6_127_96 },\n+\t\t\t{ 4, 4, MLX5_MODI_OUT_SIPV6_95_64 },\n+\t\t\t{ 4, 8, MLX5_MODI_OUT_SIPV6_63_32 },\n+\t\t\t{ 4, 12, MLX5_MODI_OUT_SIPV6_31_0 },\n+\t\t};\n+\t\t/* First mask to be modified is the mask of 4th address byte. */\n+\t\tuint32_t midx = 3;\n+\n+\t\tMLX5_ASSERT(data->offset + width <= 128);\n+\t\toff_be = 128 - (data->offset + width);\n+\t\twhile (width > 0 && midx > 0) {\n+\t\t\tif (off_be < 32) {\n+\t\t\t\tinfo[idx] = fields[midx];\n+\t\t\t\tlength = off_be + width <= 32 ?\n+\t\t\t\t\t width : 32 - off_be;\n+\t\t\t\tif (mask)\n+\t\t\t\t\tmask[midx] = flow_modify_info_mask_32\n+\t\t\t\t\t\t(length, off_be);\n+\t\t\t\telse\n+\t\t\t\t\tinfo[idx].offset = off_be;\n+\t\t\t\twidth -= length;\n+\t\t\t\toff_be = 0;\n+\t\t\t\tidx++;\n+\t\t\t} else {\n+\t\t\t\toff_be -= 32;\n \t\t\t}\n-\t\t\tinfo[idx] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SIPV6_127_96};\n-\t\t\tmask[0] = rte_cpu_to_be_32(0xffffffff >> (32 - width));\n-\t\t} else {\n-\t\t\tif (data->offset < 32)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SIPV6_31_0};\n-\t\t\tif (data->offset < 64)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SIPV6_63_32};\n-\t\t\tif (data->offset < 96)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SIPV6_95_64};\n-\t\t\tif (data->offset < 128)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_SIPV6_127_96};\n+\t\t\tmidx--;\n \t\t}\n+\t\tif (!width)\n+\t\t\tbreak;\n+\t\tinfo[idx] = fields[midx];\n+\t\tif (mask)\n+\t\t\tmask[midx] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n-\tcase RTE_FLOW_FIELD_IPV6_DST:\n-\t\tif (mask) {\n-\t\t\tif (data->offset < 32) {\n-\t\t\t\tinfo[idx] = (struct field_modify_info){4, 12,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DIPV6_31_0};\n-\t\t\t\tif (width < 32) {\n-\t\t\t\t\tmask[3] =\n-\t\t\t\t\t\trte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t\t\t (32 - width));\n-\t\t\t\t\twidth = 0;\n-\t\t\t\t} else {\n-\t\t\t\t\tmask[3] = RTE_BE32(0xffffffff);\n-\t\t\t\t\twidth -= 32;\n-\t\t\t\t}\n-\t\t\t\tif (!width)\n-\t\t\t\t\tbreak;\n-\t\t\t\t++idx;\n-\t\t\t}\n-\t\t\tif (data->offset < 64) {\n-\t\t\t\tinfo[idx] = (struct field_modify_info){4, 8,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DIPV6_63_32};\n-\t\t\t\tif (width < 32) {\n-\t\t\t\t\tmask[2] =\n-\t\t\t\t\t\trte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t\t\t (32 - width));\n-\t\t\t\t\twidth = 0;\n-\t\t\t\t} else {\n-\t\t\t\t\tmask[2] = RTE_BE32(0xffffffff);\n-\t\t\t\t\twidth -= 32;\n-\t\t\t\t}\n-\t\t\t\tif (!width)\n-\t\t\t\t\tbreak;\n-\t\t\t\t++idx;\n-\t\t\t}\n-\t\t\tif (data->offset < 96) {\n-\t\t\t\tinfo[idx] = (struct field_modify_info){4, 4,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DIPV6_95_64};\n-\t\t\t\tif (width < 32) {\n-\t\t\t\t\tmask[1] =\n-\t\t\t\t\t\trte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t\t\t (32 - width));\n-\t\t\t\t\twidth = 0;\n-\t\t\t\t} else {\n-\t\t\t\t\tmask[1] = RTE_BE32(0xffffffff);\n-\t\t\t\t\twidth -= 32;\n-\t\t\t\t}\n-\t\t\t\tif (!width)\n-\t\t\t\t\tbreak;\n-\t\t\t\t++idx;\n+\t}\n+\tcase RTE_FLOW_FIELD_IPV6_DST: {\n+\t\t/*\n+\t\t * Fields corresponding to IPv6 destination address bytes\n+\t\t * arranged according to network byte ordering.\n+\t\t */\n+\t\tstruct field_modify_info fields[] = {\n+\t\t\t{ 4, 0, MLX5_MODI_OUT_DIPV6_127_96 },\n+\t\t\t{ 4, 4, MLX5_MODI_OUT_DIPV6_95_64 },\n+\t\t\t{ 4, 8, MLX5_MODI_OUT_DIPV6_63_32 },\n+\t\t\t{ 4, 12, MLX5_MODI_OUT_DIPV6_31_0 },\n+\t\t};\n+\t\t/* First mask to be modified is the mask of 4th address byte. */\n+\t\tuint32_t midx = 3;\n+\n+\t\tMLX5_ASSERT(data->offset + width <= 128);\n+\t\toff_be = 128 - (data->offset + width);\n+\t\twhile (width > 0 && midx > 0) {\n+\t\t\tif (off_be < 32) {\n+\t\t\t\tinfo[idx] = fields[midx];\n+\t\t\t\tlength = off_be + width <= 32 ?\n+\t\t\t\t\t width : 32 - off_be;\n+\t\t\t\tif (mask)\n+\t\t\t\t\tmask[midx] = flow_modify_info_mask_32\n+\t\t\t\t\t\t(length, off_be);\n+\t\t\t\telse\n+\t\t\t\t\tinfo[idx].offset = off_be;\n+\t\t\t\twidth -= length;\n+\t\t\t\toff_be = 0;\n+\t\t\t\tidx++;\n+\t\t\t} else {\n+\t\t\t\toff_be -= 32;\n \t\t\t}\n-\t\t\tinfo[idx] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DIPV6_127_96};\n-\t\t\tmask[0] = rte_cpu_to_be_32(0xffffffff >> (32 - width));\n-\t\t} else {\n-\t\t\tif (data->offset < 32)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DIPV6_31_0};\n-\t\t\tif (data->offset < 64)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DIPV6_63_32};\n-\t\t\tif (data->offset < 96)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DIPV6_95_64};\n-\t\t\tif (data->offset < 128)\n-\t\t\t\tinfo[idx++] = (struct field_modify_info){4, 0,\n-\t\t\t\t\t\tMLX5_MODI_OUT_DIPV6_127_96};\n+\t\t\tmidx--;\n \t\t}\n+\t\tif (!width)\n+\t\t\tbreak;\n+\t\tinfo[idx] = fields[midx];\n+\t\tif (mask)\n+\t\t\tmask[midx] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n+\t}\n \tcase RTE_FLOW_FIELD_TCP_PORT_SRC:\n+\t\tMLX5_ASSERT(data->offset + width <= 16);\n+\t\toff_be = 16 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){2, 0,\n \t\t\t\t\tMLX5_MODI_OUT_TCP_SPORT};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_16(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_TCP_PORT_DST:\n+\t\tMLX5_ASSERT(data->offset + width <= 16);\n+\t\toff_be = 16 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){2, 0,\n \t\t\t\t\tMLX5_MODI_OUT_TCP_DPORT};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_16(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_TCP_SEQ_NUM:\n+\t\tMLX5_ASSERT(data->offset + width <= 32);\n+\t\toff_be = 32 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){4, 0,\n \t\t\t\t\tMLX5_MODI_OUT_TCP_SEQ_NUM};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t     (32 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_TCP_ACK_NUM:\n+\t\tMLX5_ASSERT(data->offset + width <= 32);\n+\t\toff_be = 32 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){4, 0,\n \t\t\t\t\tMLX5_MODI_OUT_TCP_ACK_NUM};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t     (32 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_TCP_FLAGS:\n+\t\tMLX5_ASSERT(data->offset + width <= 9);\n+\t\toff_be = 9 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){2, 0,\n \t\t\t\t\tMLX5_MODI_OUT_TCP_FLAGS};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_16(0x1ff >> (9 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_16(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_UDP_PORT_SRC:\n+\t\tMLX5_ASSERT(data->offset + width <= 16);\n+\t\toff_be = 16 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){2, 0,\n \t\t\t\t\tMLX5_MODI_OUT_UDP_SPORT};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_16(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_UDP_PORT_DST:\n+\t\tMLX5_ASSERT(data->offset + width <= 16);\n+\t\toff_be = 16 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){2, 0,\n \t\t\t\t\tMLX5_MODI_OUT_UDP_DPORT};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_16(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_VXLAN_VNI:\n-\t\t/* not supported yet */\n+\t\tMLX5_ASSERT(data->offset + width <= 24);\n+\t\t/* VNI is on bits 31-8 of TUNNEL_HDR_DW_1. */\n+\t\toff_be = 24 - (data->offset + width) + 8;\n+\t\tinfo[idx] = (struct field_modify_info){4, 0,\n+\t\t\t\t\tMLX5_MODI_TUNNEL_HDR_DW_1};\n+\t\tif (mask)\n+\t\t\tmask[idx] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_GENEVE_VNI:\n \t\t/* not supported yet*/\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_GTP_TEID:\n+\t\tMLX5_ASSERT(data->offset + width <= 32);\n+\t\toff_be = 32 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){4, 0,\n \t\t\t\t\tMLX5_MODI_GTP_TEID};\n \t\tif (mask)\n-\t\t\tmask[idx] = rte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t     (32 - width));\n+\t\t\tmask[idx] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_TAG:\n \t\t{\n-\t\t\tint reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG,\n-\t\t\t\t\t\t   data->level, error);\n+\t\t\tMLX5_ASSERT(data->offset + width <= 32);\n+\t\t\tint reg;\n+\n+\t\t\tif (priv->sh->config.dv_flow_en == 2)\n+\t\t\t\treg = REG_C_1;\n+\t\t\telse\n+\t\t\t\treg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG,\n+\t\t\t\t\t\t\t   data->level, error);\n \t\t\tif (reg < 0)\n \t\t\t\treturn;\n \t\t\tMLX5_ASSERT(reg != REG_NON);\n@@ -1797,15 +1794,18 @@ mlx5_flow_field_id_to_modify_info\n \t\t\tinfo[idx] = (struct field_modify_info){4, 0,\n \t\t\t\t\t\treg_to_field[reg]};\n \t\t\tif (mask)\n-\t\t\t\tmask[idx] =\n-\t\t\t\t\trte_cpu_to_be_32(0xffffffff >>\n-\t\t\t\t\t\t\t (32 - width));\n+\t\t\t\tmask[idx] = flow_modify_info_mask_32\n+\t\t\t\t\t(width, data->offset);\n+\t\t\telse\n+\t\t\t\tinfo[idx].offset = data->offset;\n \t\t}\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_MARK:\n \t\t{\n \t\t\tuint32_t mark_mask = priv->sh->dv_mark_mask;\n \t\t\tuint32_t mark_count = __builtin_popcount(mark_mask);\n+\t\t\tRTE_SET_USED(mark_count);\n+\t\t\tMLX5_ASSERT(data->offset + width <= mark_count);\n \t\t\tint reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK,\n \t\t\t\t\t\t       0, error);\n \t\t\tif (reg < 0)\n@@ -1815,14 +1815,18 @@ mlx5_flow_field_id_to_modify_info\n \t\t\tinfo[idx] = (struct field_modify_info){4, 0,\n \t\t\t\t\t\treg_to_field[reg]};\n \t\t\tif (mask)\n-\t\t\t\tmask[idx] = rte_cpu_to_be_32((mark_mask >>\n-\t\t\t\t\t (mark_count - width)) & mark_mask);\n+\t\t\t\tmask[idx] = flow_modify_info_mask_32_masked\n+\t\t\t\t\t(width, data->offset, mark_mask);\n+\t\t\telse\n+\t\t\t\tinfo[idx].offset = data->offset;\n \t\t}\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_META:\n \t\t{\n \t\t\tuint32_t meta_mask = priv->sh->dv_meta_mask;\n \t\t\tuint32_t meta_count = __builtin_popcount(meta_mask);\n+\t\t\tRTE_SET_USED(meta_count);\n+\t\t\tMLX5_ASSERT(data->offset + width <= meta_count);\n \t\t\tint reg = flow_dv_get_metadata_reg(dev, attr, error);\n \t\t\tif (reg < 0)\n \t\t\t\treturn;\n@@ -1831,16 +1835,32 @@ mlx5_flow_field_id_to_modify_info\n \t\t\tinfo[idx] = (struct field_modify_info){4, 0,\n \t\t\t\t\t\treg_to_field[reg]};\n \t\t\tif (mask)\n-\t\t\t\tmask[idx] = rte_cpu_to_be_32((meta_mask >>\n-\t\t\t\t\t(meta_count - width)) & meta_mask);\n+\t\t\t\tmask[idx] = flow_modify_info_mask_32_masked\n+\t\t\t\t\t(width, data->offset, meta_mask);\n+\t\t\telse\n+\t\t\t\tinfo[idx].offset = data->offset;\n \t\t}\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_IPV4_ECN:\n \tcase RTE_FLOW_FIELD_IPV6_ECN:\n+\t\tMLX5_ASSERT(data->offset + width <= 2);\n+\t\toff_be = 2 - (data->offset + width);\n \t\tinfo[idx] = (struct field_modify_info){1, 0,\n \t\t\t\t\tMLX5_MODI_OUT_IP_ECN};\n \t\tif (mask)\n-\t\t\tmask[idx] = 0x3 >> (2 - width);\n+\t\t\tmask[idx] = flow_modify_info_mask_8(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n+\t\tbreak;\n+\tcase RTE_FLOW_FIELD_GTP_PSC_QFI:\n+\t\tMLX5_ASSERT(data->offset + width <= 8);\n+\t\toff_be = data->offset + 8;\n+\t\tinfo[idx] = (struct field_modify_info){4, 0,\n+\t\t\t\t\tMLX5_MODI_GTPU_FIRST_EXT_DW_0};\n+\t\tif (mask)\n+\t\t\tmask[idx] = flow_modify_info_mask_32(width, off_be);\n+\t\telse\n+\t\t\tinfo[idx].offset = off_be;\n \t\tbreak;\n \tcase RTE_FLOW_FIELD_POINTER:\n \tcase RTE_FLOW_FIELD_VALUE:\n@@ -1890,7 +1910,8 @@ flow_dv_convert_action_modify_field\n \n \tif (conf->src.field == RTE_FLOW_FIELD_POINTER ||\n \t    conf->src.field == RTE_FLOW_FIELD_VALUE) {\n-\t\ttype = MLX5_MODIFICATION_TYPE_SET;\n+\t\ttype = conf->operation == RTE_FLOW_MODIFY_SET ?\n+\t\t\tMLX5_MODIFICATION_TYPE_SET : MLX5_MODIFICATION_TYPE_ADD;\n \t\t/** For SET fill the destination field (field) first. */\n \t\tmlx5_flow_field_id_to_modify_info(&conf->dst, field, mask,\n \t\t\t\t\t\t  conf->width, dev,\ndiff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c\nindex b6978bd051..3321e17fef 100644\n--- a/drivers/net/mlx5/mlx5_flow_hw.c\n+++ b/drivers/net/mlx5/mlx5_flow_hw.c\n@@ -319,6 +319,11 @@ __flow_hw_action_template_destroy(struct rte_eth_dev *dev,\n \t\tmlx5_hlist_unregister(priv->sh->flow_tbls, &grp->entry);\n \t\tacts->jump = NULL;\n \t}\n+\tif (acts->mhdr) {\n+\t\tif (acts->mhdr->action)\n+\t\t\tmlx5dr_action_destroy(acts->mhdr->action);\n+\t\tmlx5_free(acts->mhdr);\n+\t}\n }\n \n /**\n@@ -425,6 +430,37 @@ __flow_hw_act_data_encap_append(struct mlx5_priv *priv,\n \treturn 0;\n }\n \n+static __rte_always_inline int\n+__flow_hw_act_data_hdr_modify_append(struct mlx5_priv *priv,\n+\t\t\t\t     struct mlx5_hw_actions *acts,\n+\t\t\t\t     enum rte_flow_action_type type,\n+\t\t\t\t     uint16_t action_src,\n+\t\t\t\t     uint16_t action_dst,\n+\t\t\t\t     uint16_t mhdr_cmds_off,\n+\t\t\t\t     uint16_t mhdr_cmds_end,\n+\t\t\t\t     bool shared,\n+\t\t\t\t     struct field_modify_info *field,\n+\t\t\t\t     struct field_modify_info *dcopy,\n+\t\t\t\t     uint32_t *mask)\n+{\n+\tstruct mlx5_action_construct_data *act_data;\n+\n+\tact_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst);\n+\tif (!act_data)\n+\t\treturn -1;\n+\tact_data->modify_header.mhdr_cmds_off = mhdr_cmds_off;\n+\tact_data->modify_header.mhdr_cmds_end = mhdr_cmds_end;\n+\tact_data->modify_header.shared = shared;\n+\trte_memcpy(act_data->modify_header.field, field,\n+\t\t   sizeof(*field) * MLX5_ACT_MAX_MOD_FIELDS);\n+\trte_memcpy(act_data->modify_header.dcopy, dcopy,\n+\t\t   sizeof(*dcopy) * MLX5_ACT_MAX_MOD_FIELDS);\n+\trte_memcpy(act_data->modify_header.mask, mask,\n+\t\t   sizeof(*mask) * MLX5_ACT_MAX_MOD_FIELDS);\n+\tLIST_INSERT_HEAD(&acts->act_list, act_data, next);\n+\treturn 0;\n+}\n+\n /**\n  * Append shared RSS action to the dynamic action list.\n  *\n@@ -515,6 +551,265 @@ flow_hw_shared_action_translate(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+static __rte_always_inline bool\n+flow_hw_action_modify_field_is_shared(const struct rte_flow_action *action,\n+\t\t\t\t      const struct rte_flow_action *mask)\n+{\n+\tconst struct rte_flow_action_modify_field *v = action->conf;\n+\tconst struct rte_flow_action_modify_field *m = mask->conf;\n+\n+\tif (v->src.field == RTE_FLOW_FIELD_VALUE) {\n+\t\tuint32_t j;\n+\n+\t\tif (m == NULL)\n+\t\t\treturn false;\n+\t\tfor (j = 0; j < RTE_DIM(m->src.value); ++j) {\n+\t\t\t/*\n+\t\t\t * Immediate value is considered to be masked\n+\t\t\t * (and thus shared by all flow rules), if mask\n+\t\t\t * is non-zero. Partial mask over immediate value\n+\t\t\t * is not allowed.\n+\t\t\t */\n+\t\t\tif (m->src.value[j])\n+\t\t\t\treturn true;\n+\t\t}\n+\t\treturn false;\n+\t}\n+\tif (v->src.field == RTE_FLOW_FIELD_POINTER)\n+\t\treturn m->src.pvalue != NULL;\n+\t/*\n+\t * Source field types other than VALUE and\n+\t * POINTER are always shared.\n+\t */\n+\treturn true;\n+}\n+\n+static __rte_always_inline bool\n+flow_hw_should_insert_nop(const struct mlx5_hw_modify_header_action *mhdr,\n+\t\t\t  const struct mlx5_modification_cmd *cmd)\n+{\n+\tstruct mlx5_modification_cmd last_cmd = { { 0 } };\n+\tstruct mlx5_modification_cmd new_cmd = { { 0 } };\n+\tconst uint32_t cmds_num = mhdr->mhdr_cmds_num;\n+\tunsigned int last_type;\n+\tbool should_insert = false;\n+\n+\tif (cmds_num == 0)\n+\t\treturn false;\n+\tlast_cmd = *(&mhdr->mhdr_cmds[cmds_num - 1]);\n+\tlast_cmd.data0 = rte_be_to_cpu_32(last_cmd.data0);\n+\tlast_cmd.data1 = rte_be_to_cpu_32(last_cmd.data1);\n+\tlast_type = last_cmd.action_type;\n+\tnew_cmd = *cmd;\n+\tnew_cmd.data0 = rte_be_to_cpu_32(new_cmd.data0);\n+\tnew_cmd.data1 = rte_be_to_cpu_32(new_cmd.data1);\n+\tswitch (new_cmd.action_type) {\n+\tcase MLX5_MODIFICATION_TYPE_SET:\n+\tcase MLX5_MODIFICATION_TYPE_ADD:\n+\t\tif (last_type == MLX5_MODIFICATION_TYPE_SET ||\n+\t\t    last_type == MLX5_MODIFICATION_TYPE_ADD)\n+\t\t\tshould_insert = new_cmd.field == last_cmd.field;\n+\t\telse if (last_type == MLX5_MODIFICATION_TYPE_COPY)\n+\t\t\tshould_insert = new_cmd.field == last_cmd.dst_field;\n+\t\telse if (last_type == MLX5_MODIFICATION_TYPE_NOP)\n+\t\t\tshould_insert = false;\n+\t\telse\n+\t\t\tMLX5_ASSERT(false); /* Other types are not supported. */\n+\t\tbreak;\n+\tcase MLX5_MODIFICATION_TYPE_COPY:\n+\t\tif (last_type == MLX5_MODIFICATION_TYPE_SET ||\n+\t\t    last_type == MLX5_MODIFICATION_TYPE_ADD)\n+\t\t\tshould_insert = (new_cmd.field == last_cmd.field ||\n+\t\t\t\t\t new_cmd.dst_field == last_cmd.field);\n+\t\telse if (last_type == MLX5_MODIFICATION_TYPE_COPY)\n+\t\t\tshould_insert = (new_cmd.field == last_cmd.dst_field ||\n+\t\t\t\t\t new_cmd.dst_field == last_cmd.dst_field);\n+\t\telse if (last_type == MLX5_MODIFICATION_TYPE_NOP)\n+\t\t\tshould_insert = false;\n+\t\telse\n+\t\t\tMLX5_ASSERT(false); /* Other types are not supported. */\n+\t\tbreak;\n+\tdefault:\n+\t\t/* Other action types should be rejected on AT validation. */\n+\t\tMLX5_ASSERT(false);\n+\t\tbreak;\n+\t}\n+\treturn should_insert;\n+}\n+\n+static __rte_always_inline int\n+flow_hw_mhdr_cmd_nop_append(struct mlx5_hw_modify_header_action *mhdr)\n+{\n+\tstruct mlx5_modification_cmd *nop;\n+\tuint32_t num = mhdr->mhdr_cmds_num;\n+\n+\tif (num + 1 >= MLX5_MHDR_MAX_CMD)\n+\t\treturn -ENOMEM;\n+\tnop = mhdr->mhdr_cmds + num;\n+\tnop->data0 = 0;\n+\tnop->action_type = MLX5_MODIFICATION_TYPE_NOP;\n+\tnop->data0 = rte_cpu_to_be_32(nop->data0);\n+\tnop->data1 = 0;\n+\tmhdr->mhdr_cmds_num = num + 1;\n+\treturn 0;\n+}\n+\n+static __rte_always_inline int\n+flow_hw_mhdr_cmd_append(struct mlx5_hw_modify_header_action *mhdr,\n+\t\t\tstruct mlx5_modification_cmd *cmd)\n+{\n+\tuint32_t num = mhdr->mhdr_cmds_num;\n+\n+\tif (num + 1 >= MLX5_MHDR_MAX_CMD)\n+\t\treturn -ENOMEM;\n+\tmhdr->mhdr_cmds[num] = *cmd;\n+\tmhdr->mhdr_cmds_num = num + 1;\n+\treturn 0;\n+}\n+\n+static __rte_always_inline int\n+flow_hw_converted_mhdr_cmds_append(struct mlx5_hw_modify_header_action *mhdr,\n+\t\t\t\t   struct mlx5_flow_dv_modify_hdr_resource *resource)\n+{\n+\tuint32_t idx;\n+\tint ret;\n+\n+\tfor (idx = 0; idx < resource->actions_num; ++idx) {\n+\t\tstruct mlx5_modification_cmd *src = &resource->actions[idx];\n+\n+\t\tif (flow_hw_should_insert_nop(mhdr, src)) {\n+\t\t\tret = flow_hw_mhdr_cmd_nop_append(mhdr);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\t\tret = flow_hw_mhdr_cmd_append(mhdr, src);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+static __rte_always_inline void\n+flow_hw_modify_field_init(struct mlx5_hw_modify_header_action *mhdr,\n+\t\t\t  struct rte_flow_actions_template *at)\n+{\n+\tmemset(mhdr, 0, sizeof(*mhdr));\n+\t/* Modify header action without any commands is shared by default. */\n+\tmhdr->shared = true;\n+\tmhdr->pos = at->mhdr_off;\n+}\n+\n+static __rte_always_inline int\n+flow_hw_modify_field_compile(struct rte_eth_dev *dev,\n+\t\t\t     const struct rte_flow_attr *attr,\n+\t\t\t     const struct rte_flow_action *action_start, /* Start of AT actions. */\n+\t\t\t     const struct rte_flow_action *action, /* Current action from AT. */\n+\t\t\t     const struct rte_flow_action *action_mask, /* Current mask from AT. */\n+\t\t\t     struct mlx5_hw_actions *acts,\n+\t\t\t     struct mlx5_hw_modify_header_action *mhdr,\n+\t\t\t     struct rte_flow_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tconst struct rte_flow_action_modify_field *conf = action->conf;\n+\tunion {\n+\t\tstruct mlx5_flow_dv_modify_hdr_resource resource;\n+\t\tuint8_t data[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +\n+\t\t\t     sizeof(struct mlx5_modification_cmd) * MLX5_MHDR_MAX_CMD];\n+\t} dummy;\n+\tstruct mlx5_flow_dv_modify_hdr_resource *resource;\n+\tstruct rte_flow_item item = {\n+\t\t.spec = NULL,\n+\t\t.mask = NULL\n+\t};\n+\tstruct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = {\n+\t\t\t\t\t\t{0, 0, MLX5_MODI_OUT_NONE} };\n+\tstruct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = {\n+\t\t\t\t\t\t{0, 0, MLX5_MODI_OUT_NONE} };\n+\tuint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = { 0 };\n+\tuint32_t type, value = 0;\n+\tuint16_t cmds_start, cmds_end;\n+\tbool shared;\n+\tint ret;\n+\n+\t/*\n+\t * Modify header action is shared if previous modify_field actions\n+\t * are shared and currently compiled action is shared.\n+\t */\n+\tshared = flow_hw_action_modify_field_is_shared(action, action_mask);\n+\tmhdr->shared &= shared;\n+\tif (conf->src.field == RTE_FLOW_FIELD_POINTER ||\n+\t    conf->src.field == RTE_FLOW_FIELD_VALUE) {\n+\t\ttype = conf->operation == RTE_FLOW_MODIFY_SET ? MLX5_MODIFICATION_TYPE_SET :\n+\t\t\t\t\t\t\t\tMLX5_MODIFICATION_TYPE_ADD;\n+\t\t/* For SET/ADD fill the destination field (field) first. */\n+\t\tmlx5_flow_field_id_to_modify_info(&conf->dst, field, mask,\n+\t\t\t\t\t\t  conf->width, dev,\n+\t\t\t\t\t\t  attr, error);\n+\t\titem.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ?\n+\t\t\t\t(void *)(uintptr_t)conf->src.pvalue :\n+\t\t\t\t(void *)(uintptr_t)&conf->src.value;\n+\t\tif (conf->dst.field == RTE_FLOW_FIELD_META ||\n+\t\t    conf->dst.field == RTE_FLOW_FIELD_TAG) {\n+\t\t\tvalue = *(const unaligned_uint32_t *)item.spec;\n+\t\t\tvalue = rte_cpu_to_be_32(value);\n+\t\t\titem.spec = &value;\n+\t\t} else if (conf->dst.field == RTE_FLOW_FIELD_GTP_PSC_QFI) {\n+\t\t\t/*\n+\t\t\t * QFI is passed as an uint8_t integer, but it is accessed through\n+\t\t\t * a 2nd least significant byte of a 32-bit field in modify header command.\n+\t\t\t */\n+\t\t\tvalue = *(const uint8_t *)item.spec;\n+\t\t\tvalue = rte_cpu_to_be_32(value << 8);\n+\t\t\titem.spec = &value;\n+\t\t}\n+\t} else {\n+\t\ttype = MLX5_MODIFICATION_TYPE_COPY;\n+\t\t/* For COPY fill the destination field (dcopy) without mask. */\n+\t\tmlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL,\n+\t\t\t\t\t\t  conf->width, dev,\n+\t\t\t\t\t\t  attr, error);\n+\t\t/* Then construct the source field (field) with mask. */\n+\t\tmlx5_flow_field_id_to_modify_info(&conf->src, field, mask,\n+\t\t\t\t\t\t  conf->width, dev,\n+\t\t\t\t\t\t  attr, error);\n+\t}\n+\titem.mask = &mask;\n+\tmemset(&dummy, 0, sizeof(dummy));\n+\tresource = &dummy.resource;\n+\tret = flow_dv_convert_modify_action(&item, field, dcopy, resource, type, error);\n+\tif (ret)\n+\t\treturn ret;\n+\tMLX5_ASSERT(resource->actions_num > 0);\n+\t/*\n+\t * If previous modify field action collide with this one, then insert NOP command.\n+\t * This NOP command will not be a part of action's command range used to update commands\n+\t * on rule creation.\n+\t */\n+\tif (flow_hw_should_insert_nop(mhdr, &resource->actions[0])) {\n+\t\tret = flow_hw_mhdr_cmd_nop_append(mhdr);\n+\t\tif (ret)\n+\t\t\treturn rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t\t  NULL, \"too many modify field operations specified\");\n+\t}\n+\tcmds_start = mhdr->mhdr_cmds_num;\n+\tret = flow_hw_converted_mhdr_cmds_append(mhdr, resource);\n+\tif (ret)\n+\t\treturn rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t  NULL, \"too many modify field operations specified\");\n+\n+\tcmds_end = mhdr->mhdr_cmds_num;\n+\tif (shared)\n+\t\treturn 0;\n+\tret = __flow_hw_act_data_hdr_modify_append(priv, acts, RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,\n+\t\t\t\t\t\t   action - action_start, mhdr->pos,\n+\t\t\t\t\t\t   cmds_start, cmds_end, shared,\n+\t\t\t\t\t\t   field, dcopy, mask);\n+\tif (ret)\n+\t\treturn rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t  NULL, \"not enough memory to store modify field metadata\");\n+\treturn 0;\n+}\n+\n /**\n  * Translate rte_flow actions to DR action.\n  *\n@@ -558,10 +853,12 @@ flow_hw_actions_translate(struct rte_eth_dev *dev,\n \tuint16_t reformat_pos = MLX5_HW_MAX_ACTS, reformat_src = 0;\n \tuint8_t *encap_data = NULL, *encap_data_m = NULL;\n \tsize_t data_size = 0;\n+\tstruct mlx5_hw_modify_header_action mhdr = { 0 };\n \tbool actions_end = false;\n \tuint32_t type, i;\n \tint err;\n \n+\tflow_hw_modify_field_init(&mhdr, at);\n \tif (attr->transfer)\n \t\ttype = MLX5DR_TABLE_TYPE_FDB;\n \telse if (attr->egress)\n@@ -714,6 +1011,15 @@ flow_hw_actions_translate(struct rte_eth_dev *dev,\n \t\t\treformat_pos = i++;\n \t\t\trefmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2;\n \t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:\n+\t\t\tif (mhdr.pos == UINT16_MAX)\n+\t\t\t\tmhdr.pos = i++;\n+\t\t\terr = flow_hw_modify_field_compile(dev, attr, action_start,\n+\t\t\t\t\t\t\t   actions, masks, acts, &mhdr,\n+\t\t\t\t\t\t\t   error);\n+\t\t\tif (err)\n+\t\t\t\tgoto err;\n+\t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_END:\n \t\t\tactions_end = true;\n \t\t\tbreak;\n@@ -721,6 +1027,31 @@ flow_hw_actions_translate(struct rte_eth_dev *dev,\n \t\t\tbreak;\n \t\t}\n \t}\n+\tif (mhdr.pos != UINT16_MAX) {\n+\t\tuint32_t flags;\n+\t\tuint32_t bulk_size;\n+\t\tsize_t mhdr_len;\n+\n+\t\tacts->mhdr = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*acts->mhdr),\n+\t\t\t\t\t 0, SOCKET_ID_ANY);\n+\t\tif (!acts->mhdr)\n+\t\t\tgoto err;\n+\t\trte_memcpy(acts->mhdr, &mhdr, sizeof(*acts->mhdr));\n+\t\tmhdr_len = sizeof(struct mlx5_modification_cmd) * acts->mhdr->mhdr_cmds_num;\n+\t\tflags = mlx5_hw_act_flag[!!attr->group][type];\n+\t\tif (acts->mhdr->shared) {\n+\t\t\tflags |= MLX5DR_ACTION_FLAG_SHARED;\n+\t\t\tbulk_size = 0;\n+\t\t} else {\n+\t\t\tbulk_size = rte_log2_u32(table_attr->nb_flows);\n+\t\t}\n+\t\tacts->mhdr->action = mlx5dr_action_create_modify_header\n+\t\t\t\t(priv->dr_ctx, mhdr_len, (__be64 *)acts->mhdr->mhdr_cmds,\n+\t\t\t\t bulk_size, flags);\n+\t\tif (!acts->mhdr->action)\n+\t\t\tgoto err;\n+\t\tacts->rule_acts[acts->mhdr->pos].action = acts->mhdr->action;\n+\t}\n \tif (reformat_pos != MLX5_HW_MAX_ACTS) {\n \t\tuint8_t buf[MLX5_ENCAP_MAX_LEN];\n \t\tbool shared_rfmt = true;\n@@ -884,6 +1215,110 @@ flow_hw_shared_action_construct(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+static __rte_always_inline int\n+flow_hw_mhdr_cmd_is_nop(const struct mlx5_modification_cmd *cmd)\n+{\n+\tstruct mlx5_modification_cmd cmd_he = {\n+\t\t.data0 = rte_be_to_cpu_32(cmd->data0),\n+\t\t.data1 = 0,\n+\t};\n+\n+\treturn cmd_he.action_type == MLX5_MODIFICATION_TYPE_NOP;\n+}\n+\n+/**\n+ * Construct flow action array.\n+ *\n+ * For action template contains dynamic actions, these actions need to\n+ * be updated according to the rte_flow action during flow creation.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the rte_eth_dev structure.\n+ * @param[in] job\n+ *   Pointer to job descriptor.\n+ * @param[in] hw_acts\n+ *   Pointer to translated actions from template.\n+ * @param[in] it_idx\n+ *   Item template index the action template refer to.\n+ * @param[in] actions\n+ *   Array of rte_flow action need to be checked.\n+ * @param[in] rule_acts\n+ *   Array of DR rule actions to be used during flow creation..\n+ * @param[in] acts_num\n+ *   Pointer to the real acts_num flow has.\n+ *\n+ * @return\n+ *    0 on success, negative value otherwise and rte_errno is set.\n+ */\n+static __rte_always_inline int\n+flow_hw_modify_field_construct(struct mlx5_hw_q_job *job,\n+\t\t\t       struct mlx5_action_construct_data *act_data,\n+\t\t\t       const struct mlx5_hw_actions *hw_acts,\n+\t\t\t       const struct rte_flow_action *action)\n+{\n+\tconst struct rte_flow_action_modify_field *mhdr_action = action->conf;\n+\tuint8_t values[16] = { 0 };\n+\tunaligned_uint32_t *value_p;\n+\tuint32_t i;\n+\tstruct field_modify_info *field;\n+\n+\tif (!hw_acts->mhdr)\n+\t\treturn -1;\n+\tif (hw_acts->mhdr->shared || act_data->modify_header.shared)\n+\t\treturn 0;\n+\tMLX5_ASSERT(mhdr_action->operation == RTE_FLOW_MODIFY_SET ||\n+\t\t    mhdr_action->operation == RTE_FLOW_MODIFY_ADD);\n+\tif (mhdr_action->src.field != RTE_FLOW_FIELD_VALUE &&\n+\t    mhdr_action->src.field != RTE_FLOW_FIELD_POINTER)\n+\t\treturn 0;\n+\tif (mhdr_action->src.field == RTE_FLOW_FIELD_VALUE)\n+\t\trte_memcpy(values, &mhdr_action->src.value, sizeof(values));\n+\telse\n+\t\trte_memcpy(values, mhdr_action->src.pvalue, sizeof(values));\n+\tif (mhdr_action->dst.field == RTE_FLOW_FIELD_META ||\n+\t    mhdr_action->dst.field == RTE_FLOW_FIELD_TAG) {\n+\t\tvalue_p = (unaligned_uint32_t *)values;\n+\t\t*value_p = rte_cpu_to_be_32(*value_p);\n+\t} else if (mhdr_action->dst.field == RTE_FLOW_FIELD_GTP_PSC_QFI) {\n+\t\tuint32_t tmp;\n+\n+\t\t/*\n+\t\t * QFI is passed as an uint8_t integer, but it is accessed through\n+\t\t * a 2nd least significant byte of a 32-bit field in modify header command.\n+\t\t */\n+\t\ttmp = values[0];\n+\t\tvalue_p = (unaligned_uint32_t *)values;\n+\t\t*value_p = rte_cpu_to_be_32(tmp << 8);\n+\t}\n+\ti = act_data->modify_header.mhdr_cmds_off;\n+\tfield = act_data->modify_header.field;\n+\tdo {\n+\t\tuint32_t off_b;\n+\t\tuint32_t mask;\n+\t\tuint32_t data;\n+\t\tconst uint8_t *mask_src;\n+\n+\t\tif (i >= act_data->modify_header.mhdr_cmds_end)\n+\t\t\treturn -1;\n+\t\tif (flow_hw_mhdr_cmd_is_nop(&job->mhdr_cmd[i])) {\n+\t\t\t++i;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tmask_src = (const uint8_t *)act_data->modify_header.mask;\n+\t\tmask = flow_dv_fetch_field(mask_src + field->offset, field->size);\n+\t\tif (!mask) {\n+\t\t\t++field;\n+\t\t\tcontinue;\n+\t\t}\n+\t\toff_b = rte_bsf32(mask);\n+\t\tdata = flow_dv_fetch_field(values + field->offset, field->size);\n+\t\tdata = (data & mask) >> off_b;\n+\t\tjob->mhdr_cmd[i++].data1 = rte_cpu_to_be_32(data);\n+\t\t++field;\n+\t} while (field->size);\n+\treturn 0;\n+}\n+\n /**\n  * Construct flow action array.\n  *\n@@ -928,6 +1363,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,\n \t};\n \tuint32_t ft_flag;\n \tsize_t encap_len = 0;\n+\tint ret;\n \n \tmemcpy(rule_acts, hw_acts->rule_acts,\n \t       sizeof(*rule_acts) * hw_acts->acts_num);\n@@ -945,6 +1381,18 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,\n \t} else {\n \t\tattr.ingress = 1;\n \t}\n+\tif (hw_acts->mhdr && hw_acts->mhdr->mhdr_cmds_num > 0) {\n+\t\tuint16_t pos = hw_acts->mhdr->pos;\n+\n+\t\tif (!hw_acts->mhdr->shared) {\n+\t\t\trule_acts[pos].modify_header.offset =\n+\t\t\t\t\t\tjob->flow->idx - 1;\n+\t\t\trule_acts[pos].modify_header.data =\n+\t\t\t\t\t\t(uint8_t *)job->mhdr_cmd;\n+\t\t\trte_memcpy(job->mhdr_cmd, hw_acts->mhdr->mhdr_cmds,\n+\t\t\t\t   sizeof(*job->mhdr_cmd) * hw_acts->mhdr->mhdr_cmds_num);\n+\t\t}\n+\t}\n \tLIST_FOREACH(act_data, &hw_acts->act_list, next) {\n \t\tuint32_t jump_group;\n \t\tuint32_t tag;\n@@ -1020,6 +1468,14 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,\n \t\t\tMLX5_ASSERT(raw_encap_data->size ==\n \t\t\t\t    act_data->encap.len);\n \t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:\n+\t\t\tret = flow_hw_modify_field_construct(job,\n+\t\t\t\t\t\t\t     act_data,\n+\t\t\t\t\t\t\t     hw_acts,\n+\t\t\t\t\t\t\t     action);\n+\t\t\tif (ret)\n+\t\t\t\treturn -1;\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n@@ -1609,6 +2065,136 @@ flow_hw_table_destroy(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+static int\n+flow_hw_validate_action_modify_field(const struct rte_flow_action *action,\n+\t\t\t\t     const struct rte_flow_action *mask,\n+\t\t\t\t     struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_action_modify_field *action_conf =\n+\t\taction->conf;\n+\tconst struct rte_flow_action_modify_field *mask_conf =\n+\t\tmask->conf;\n+\n+\tif (action_conf->operation != mask_conf->operation)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, action,\n+\t\t\t\t\"modify_field operation mask and template are not equal\");\n+\tif (action_conf->dst.field != mask_conf->dst.field)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, action,\n+\t\t\t\t\"destination field mask and template are not equal\");\n+\tif (action_conf->dst.field == RTE_FLOW_FIELD_POINTER ||\n+\t    action_conf->dst.field == RTE_FLOW_FIELD_VALUE)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, action,\n+\t\t\t\t\"immediate value and pointer cannot be used as destination\");\n+\tif (mask_conf->dst.level != UINT32_MAX)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, action,\n+\t\t\t\"destination encapsulation level must be fully masked\");\n+\tif (mask_conf->dst.offset != UINT32_MAX)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, action,\n+\t\t\t\"destination offset level must be fully masked\");\n+\tif (action_conf->src.field != mask_conf->src.field)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, action,\n+\t\t\t\t\"destination field mask and template are not equal\");\n+\tif (action_conf->src.field != RTE_FLOW_FIELD_POINTER &&\n+\t    action_conf->src.field != RTE_FLOW_FIELD_VALUE) {\n+\t\tif (mask_conf->src.level != UINT32_MAX)\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, action,\n+\t\t\t\t\"source encapsulation level must be fully masked\");\n+\t\tif (mask_conf->src.offset != UINT32_MAX)\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, action,\n+\t\t\t\t\"source offset level must be fully masked\");\n+\t}\n+\tif (mask_conf->width != UINT32_MAX)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, action,\n+\t\t\t\t\"modify_field width field must be fully masked\");\n+\treturn 0;\n+}\n+\n+static int\n+flow_hw_action_validate(const struct rte_flow_action actions[],\n+\t\t\tconst struct rte_flow_action masks[],\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tint i;\n+\tbool actions_end = false;\n+\tint ret;\n+\n+\tfor (i = 0; !actions_end; ++i) {\n+\t\tconst struct rte_flow_action *action = &actions[i];\n+\t\tconst struct rte_flow_action *mask = &masks[i];\n+\n+\t\tif (action->type != mask->type)\n+\t\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\t  action,\n+\t\t\t\t\t\t  \"mask type does not match action type\");\n+\t\tswitch (action->type) {\n+\t\tcase RTE_FLOW_ACTION_TYPE_VOID:\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_INDIRECT:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_MARK:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_JUMP:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_RAW_ENCAP:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_RAW_DECAP:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:\n+\t\t\tret = flow_hw_validate_action_modify_field(action,\n+\t\t\t\t\t\t\t\t\tmask,\n+\t\t\t\t\t\t\t\t\terror);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_END:\n+\t\t\tactions_end = true;\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+\t\t\t\t\t\t  action,\n+\t\t\t\t\t\t  \"action not supported in template API\");\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n /**\n  * Create flow action template.\n  *\n@@ -1637,6 +2223,8 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev,\n \tint len, act_len, mask_len, i;\n \tstruct rte_flow_actions_template *at;\n \n+\tif (flow_hw_action_validate(actions, masks, error))\n+\t\treturn NULL;\n \tact_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS,\n \t\t\t\tNULL, 0, actions, error);\n \tif (act_len <= 0)\n@@ -2093,6 +2681,8 @@ flow_hw_configure(struct rte_eth_dev *dev,\n \t\t}\n \t\tmem_size += (sizeof(struct mlx5_hw_q_job *) +\n \t\t\t    sizeof(uint8_t) * MLX5_ENCAP_MAX_LEN +\n+\t\t\t    sizeof(struct mlx5_modification_cmd) *\n+\t\t\t    MLX5_MHDR_MAX_CMD +\n \t\t\t    sizeof(struct mlx5_hw_q_job)) *\n \t\t\t    queue_attr[0]->size;\n \t}\n@@ -2104,6 +2694,7 @@ flow_hw_configure(struct rte_eth_dev *dev,\n \t}\n \tfor (i = 0; i < nb_queue; i++) {\n \t\tuint8_t *encap = NULL;\n+\t\tstruct mlx5_modification_cmd *mhdr_cmd = NULL;\n \n \t\tpriv->hw_q[i].job_idx = queue_attr[i]->size;\n \t\tpriv->hw_q[i].size = queue_attr[i]->size;\n@@ -2115,8 +2706,10 @@ flow_hw_configure(struct rte_eth_dev *dev,\n \t\t\t\t\t    &job[queue_attr[i - 1]->size];\n \t\tjob = (struct mlx5_hw_q_job *)\n \t\t      &priv->hw_q[i].job[queue_attr[i]->size];\n-\t\tencap = (uint8_t *)&job[queue_attr[i]->size];\n+\t\tmhdr_cmd = (struct mlx5_modification_cmd *)&job[queue_attr[i]->size];\n+\t\tencap = (uint8_t *)&mhdr_cmd[queue_attr[i]->size * MLX5_MHDR_MAX_CMD];\n \t\tfor (j = 0; j < queue_attr[i]->size; j++) {\n+\t\t\tjob[j].mhdr_cmd = &mhdr_cmd[j * MLX5_MHDR_MAX_CMD];\n \t\t\tjob[j].encap_data = &encap[j * MLX5_ENCAP_MAX_LEN];\n \t\t\tpriv->hw_q[i].job[j] = &job[j];\n \t\t}\n",
    "prefixes": [
        "v2",
        "04/17"
    ]
}