get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 102453,
    "url": "http://patches.dpdk.org/api/patches/102453/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20211020151457.17577-5-viacheslavo@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": "<20211020151457.17577-5-viacheslavo@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20211020151457.17577-5-viacheslavo@nvidia.com",
    "date": "2021-10-20T15:14:57",
    "name": "[v8,4/4] app/testpmd: add flex item CLI commands",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "d83b82de8b9a83519fbef2302976175384dd7255",
    "submitter": {
        "id": 1926,
        "url": "http://patches.dpdk.org/api/people/1926/?format=api",
        "name": "Slava Ovsiienko",
        "email": "viacheslavo@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/20211020151457.17577-5-viacheslavo@nvidia.com/mbox/",
    "series": [
        {
            "id": 19846,
            "url": "http://patches.dpdk.org/api/series/19846/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=19846",
            "date": "2021-10-20T15:14:53",
            "name": "ethdev: introduce configurable flexible item",
            "version": 8,
            "mbox": "http://patches.dpdk.org/series/19846/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/102453/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/102453/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 8FD13A0C43;\n\tWed, 20 Oct 2021 17:16:19 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id E0ED241257;\n\tWed, 20 Oct 2021 17:16:02 +0200 (CEST)",
            "from NAM12-BN8-obe.outbound.protection.outlook.com\n (mail-bn8nam12on2081.outbound.protection.outlook.com [40.107.237.81])\n by mails.dpdk.org (Postfix) with ESMTP id 983084124E\n for <dev@dpdk.org>; Wed, 20 Oct 2021 17:16:01 +0200 (CEST)",
            "from BN6PR19CA0050.namprd19.prod.outlook.com (2603:10b6:404:e3::12)\n by BL1PR12MB5047.namprd12.prod.outlook.com (2603:10b6:208:31a::6)\n with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4628.16; Wed, 20 Oct\n 2021 15:15:56 +0000",
            "from BN8NAM11FT021.eop-nam11.prod.protection.outlook.com\n (2603:10b6:404:e3:cafe::a5) by BN6PR19CA0050.outlook.office365.com\n (2603:10b6:404:e3::12) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4608.15 via Frontend\n Transport; Wed, 20 Oct 2021 15:15:56 +0000",
            "from mail.nvidia.com (216.228.112.34) by\n BN8NAM11FT021.mail.protection.outlook.com (10.13.177.114) with Microsoft SMTP\n Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id\n 15.20.4628.16 via Frontend Transport; Wed, 20 Oct 2021 15:15:55 +0000",
            "from nvidia.com (172.20.187.6) by HQMAIL107.nvidia.com\n (172.20.187.13) with Microsoft SMTP Server (TLS) id 15.0.1497.18; Wed, 20 Oct\n 2021 15:15:40 +0000"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=bppzHaGVL7l9e1wlf/MwbVANsAxcy0u/S1g/6ezkNCa+cMnQlRJSCDKO/O4w/x7zCZsH87dUNA2xLWeEMfsmpQonCl7D7n17ADqM8dQ9NjwbqJB5iD/0TyFUYcOAmfRmd4BF5frPCzHerqyfIAXaqm5QSI4XNfcE73glYxp7JQprVc8rf0XiFij05I7Bk8ml79MB3XbG3Vp+ZEgnAE0hvW1NlEmZ5FW5vORyVLZ0K6Ad82CydKZMTrBRPJRCgX4bFYbQ1PX/CY38oUd5glScUm15eZEhOdpnu7zI+8WY3e+PRFGRQGY4ErtAZCkuQQuBbJHmG9geb9FUvsuk5WXCnA==",
        "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=7QWBsEgoqFfqW7MQWj8JVyTqkHQusI6JaLQyDH07QrI=;\n b=oQ10TdGEUEKBx1W0WhIexfzaS4Lw7vGF2wUewSrY5K8L7bJhj4QS0GRi1dRYhEBPkhhmm9sr8bVLN4HsYbJmabb3cSGkvd/3K7vBsdRA8RnDmLwCfiawzSu1O0AFRUaR0Ia9o+Batd07oDfNUBGmukBH9GPZXiofANPUmkxgfzuUKQYIaB/XFzExUf3pbUQ1omGXIRmx4ghnwTXgq8PDeDbJHM4KSxRYOBV7SM6IISopflBEDqJ51ybQ8GI52Z24rbJa2MQ7K2Ak0cm2u/jLxvNk0QcKEJu4FrNT00INojXxU/iRlN/sE1xrlGdricIAOF7Or3NSoZGxCYLFxHmw1A==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass (sender ip is\n 216.228.112.34) smtp.rcpttodomain=monjalon.net smtp.mailfrom=nvidia.com;\n dmarc=pass (p=quarantine sp=quarantine pct=100) action=none\n header.from=nvidia.com; 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=7QWBsEgoqFfqW7MQWj8JVyTqkHQusI6JaLQyDH07QrI=;\n b=Ai+bs4AWAtwPrWjaJ+tySmgruUPhadDCHPGzORa9PVVHKL58MkgMyFwcxKZ3mkxUuL451ruaC00IRpdYUgGZZb59wn2d7GEzQgUZXC9u7EzLzsDfOHaMlL5WzyGc5rXNEAN+zTMo7tk/T+tMHrH1gHOZ6muQjx1uTaOtJPf2xQxHhlBXjw5LRb93tWeSvHPb9u+hhZyn870UTc6Ew08x2LgvhahQ/r1+I8EeiE7biVoBHXke0ecrF2XXDJIyzIcKj/1nWhsLy1pGQ7i8s0jnt4M7MEmfY/22XwNj9uCj8NL1aEl12Xs+ZNTsikFI24UNUSGzI0SLczjh9i0FonXmZw==",
        "X-MS-Exchange-Authentication-Results": "spf=pass (sender IP is 216.228.112.34)\n smtp.mailfrom=nvidia.com; monjalon.net; dkim=none (message not signed)\n header.d=none;monjalon.net; dmarc=pass action=none header.from=nvidia.com;",
        "Received-SPF": "Pass (protection.outlook.com: domain of nvidia.com designates\n 216.228.112.34 as permitted sender) receiver=protection.outlook.com;\n client-ip=216.228.112.34; helo=mail.nvidia.com;",
        "From": "Viacheslav Ovsiienko <viacheslavo@nvidia.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<rasland@nvidia.com>, <matan@nvidia.com>, <shahafs@nvidia.com>,\n <orika@nvidia.com>, <getelson@nvidia.com>, <thomas@monjalon.net>",
        "Date": "Wed, 20 Oct 2021 18:14:57 +0300",
        "Message-ID": "<20211020151457.17577-5-viacheslavo@nvidia.com>",
        "X-Mailer": "git-send-email 2.18.1",
        "In-Reply-To": "<20211020151457.17577-1-viacheslavo@nvidia.com>",
        "References": "<20210922180418.20663-1-viacheslavo@nvidia.com>\n <20211020151457.17577-1-viacheslavo@nvidia.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[172.20.187.6]",
        "X-ClientProxiedBy": "HQMAIL107.nvidia.com (172.20.187.13) To\n HQMAIL107.nvidia.com (172.20.187.13)",
        "X-EOPAttributedMessage": "0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-Office365-Filtering-Correlation-Id": "8df094f0-22de-4666-3fca-08d993dc83a6",
        "X-MS-TrafficTypeDiagnostic": "BL1PR12MB5047:",
        "X-LD-Processed": "43083d15-7273-40c1-b7db-39efd9ccc17a,ExtAddr",
        "X-Microsoft-Antispam-PRVS": "\n <BL1PR12MB50472BE01919A5F50D1EE4E8DFBE9@BL1PR12MB5047.namprd12.prod.outlook.com>",
        "X-MS-Oob-TLC-OOBClassifiers": "OLM:262;",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n CVvJiQuPSWc7p/DtL8KpYwJoYlJtwidFbW0VIdUK4rKJZyZ67ZfcxkbHX1tKRvYO7AHlBHH8Tcb22VE5NWzE47hAcil1dHWH1Y8jyGjlTwrLAzB/M9Pr1RdyUwKkUmMOlFqfNAPNJYIVLyayezF0kds1KX0s+D7CnL0JwicCGdMHRVC5NC+3vZGaWiYyq7GpwZJ2tcNj83Vj61tPGz2t3gHpHULZQWguVolsDldvi+eMZR8pP5o/tS2mnBcZv2OF7sijz1KPJMozt+JqcnAbBVGV6VsYWI9YiuyTKlUhKoissgq25NDaHX6u3RPcbHp3TZA8lku02emhWFuQMq90WkIYQ4/rHq+a1hyy7S5sbksiYZyjejZ41oMTr928igDC+rGkrr3wxRFtXVKaknJxrhQQYnF+/+kVZrimZ4j4NAcR+ShUUdPFdaRG9U9xtZscTQale//Sba/L0gWD90/giqPV8vp7DIatt37df/kE7fHIg7gQSBrTsv4Ugk9wYtmfkg1TeY2m7+nK77lofZc48lcVPCLOALO9EqksBVowC4EjCF+rL2OyrZycw2boTiK0BvvAYCjmOX7LilO/hK+gD2zU2zydWaqcNneQfoZ2S01mtwSsyNYMtrAmToZzE7mdcqCR8GzOHiK8NHpZTDfsex4IVIdbiYX7WA8f1+HJ9IIt0Tg8kvIJjutoRljQwv0SyE3FIfi/a+auPSDTgmnHlg==",
        "X-Forefront-Antispam-Report": "CIP:216.228.112.34; CTRY:US; LANG:en; SCL:1;\n SRV:;\n IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:schybrid03.nvidia.com; CAT:NONE;\n SFS:(4636009)(36840700001)(46966006)(8676002)(508600001)(83380400001)(7636003)(82310400003)(70206006)(7696005)(47076005)(36906005)(30864003)(5660300002)(36860700001)(6916009)(186003)(54906003)(16526019)(2616005)(336012)(356005)(1076003)(4326008)(70586007)(36756003)(2906002)(6666004)(8936002)(86362001)(26005)(426003)(55016002)(6286002)(316002);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "Nvidia.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "20 Oct 2021 15:15:55.6516 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 8df094f0-22de-4666-3fca-08d993dc83a6",
        "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.112.34];\n Helo=[mail.nvidia.com]",
        "X-MS-Exchange-CrossTenant-AuthSource": "\n BN8NAM11FT021.eop-nam11.prod.protection.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "BL1PR12MB5047",
        "Subject": "[dpdk-dev] [PATCH v8 4/4] app/testpmd: add flex item CLI commands",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Gregory Etelson <getelson@nvidia.com>\n\nNetwork port hardware is shipped with fixed number of\nsupported network protocols. If application must work with a\nprotocol that is not included in the port hardware by default, it\ncan try to add the new protocol to port hardware.\n\nFlex item or flex parser is port infrastructure that allows\napplication to add support for a custom network header and\noffload flows to match the header elements.\n\nApplication must complete the following tasks to create a flow\nrule that matches custom header:\n\n1. Create flow item object in port hardware.\nApplication must provide custom header configuration to PMD.\nPMD will use that configuration to create flex item object in\nport hardware.\n\n2. Create flex patterns to match. Flex pattern has a spec and a mask\ncomponents, like a regular flow item. Combined together, spec and mask\ncan target unique data sequence or a number of data sequences in the\ncustom header.\nFlex patterns of the same flex item can have different lengths.\nFlex pattern is identified by unique handler value.\n\n3. Create a flow rule with a flex flow item that references\nflow pattern.\n\nTestpmd flex CLI commands are:\n\ntestpmd> flow flex_item create <port> <flex_id> <filename>\n\ntestpmd> set flex_pattern <pattern_id> \\\n         spec <spec data> mask <mask data>\n\ntestpmd> set flex_pattern <pattern_id> is <spec_data>\n\ntestpmd> flow create <port> ... \\\n/ flex item is <flex_id> pattern is <pattern_id> / ...\n\nThe patch works with the jansson library API.\nA new optional dependency on jansson library is added for\ntestpmd. If jansson not detected the flex item functionality\nis disabled.\nJansson development files must be present:\njansson.pc, jansson.h libjansson.[a,so]\n\nSigned-off-by: Gregory Etelson <getelson@nvidia.com>\nReviewed-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>\n---\n app/test-pmd/cmd_flex_item.c                | 548 ++++++++++++++++++++\n app/test-pmd/cmdline.c                      |   2 +\n app/test-pmd/cmdline_flow.c                 | 223 +++++++-\n app/test-pmd/meson.build                    |   6 +\n app/test-pmd/testpmd.c                      |   2 +-\n app/test-pmd/testpmd.h                      |  30 ++\n doc/guides/testpmd_app_ug/testpmd_funcs.rst | 119 +++++\n 7 files changed, 928 insertions(+), 2 deletions(-)\n create mode 100644 app/test-pmd/cmd_flex_item.c",
    "diff": "diff --git a/app/test-pmd/cmd_flex_item.c b/app/test-pmd/cmd_flex_item.c\nnew file mode 100644\nindex 0000000000..45103e45a8\n--- /dev/null\n+++ b/app/test-pmd/cmd_flex_item.c\n@@ -0,0 +1,548 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2021 NVIDIA Corporation & Affiliates\n+ */\n+\n+#include <stddef.h>\n+#include <stdint.h>\n+#include <stdio.h>\n+#include <errno.h>\n+#include <string.h>\n+\n+#include <rte_common.h>\n+#include <rte_ethdev.h>\n+#include <cmdline_parse.h>\n+#include <cmdline_parse_string.h>\n+#include <cmdline_parse_num.h>\n+#include <rte_flow.h>\n+\n+#include \"testpmd.h\"\n+\n+struct flex_item *flex_items[RTE_MAX_ETHPORTS][FLEX_MAX_PARSERS_NUM];\n+struct flex_pattern flex_patterns[FLEX_MAX_PATTERNS_NUM];\n+\n+#ifdef RTE_HAS_JANSSON\n+static __rte_always_inline bool\n+match_strkey(const char *key, const char *pattern)\n+{\n+\treturn strncmp(key, pattern, strlen(key)) == 0;\n+}\n+\n+static struct flex_item *\n+flex_parser_fetch(uint16_t port_id, uint16_t flex_id)\n+{\n+\tif (port_id >= RTE_MAX_ETHPORTS) {\n+\t\tprintf(\"Invalid port_id: %u\\n\", port_id);\n+\t\treturn FLEX_PARSER_ERR;\n+\t}\n+\tif (flex_id >= FLEX_MAX_PARSERS_NUM) {\n+\t\tprintf(\"Invalid flex item flex_id: %u\\n\", flex_id);\n+\t\treturn FLEX_PARSER_ERR;\n+\t}\n+\treturn flex_items[port_id][flex_id];\n+}\n+\n+void\n+flex_item_destroy(portid_t port_id, uint16_t flex_id)\n+{\n+\tint ret;\n+\tstruct rte_flow_error error;\n+\tstruct flex_item *fp = flex_parser_fetch(port_id, flex_id);\n+\tif (fp == FLEX_PARSER_ERR) {\n+\t\tprintf(\"Bad parameters: port_id=%u flex_id=%u\\n\",\n+\t\t       port_id, flex_id);\n+\t\treturn;\n+\t}\n+\tif (!fp)\n+\t\treturn;\n+\tret = rte_flow_flex_item_release(port_id, fp->flex_handle, &error);\n+\tif (!ret) {\n+\t\tfree(fp);\n+\t\tflex_items[port_id][flex_id] = NULL;\n+\t\tprintf(\"port-%u: released flex item #%u\\n\",\n+\t\t       port_id, flex_id);\n+\n+\t} else {\n+\t\tprintf(\"port-%u: cannot release flex item #%u: %s\\n\",\n+\t\t       port_id, flex_id, error.message);\n+\t}\n+}\n+\n+static int\n+flex_tunnel_parse(json_t *jtun, enum rte_flow_item_flex_tunnel_mode *tunnel)\n+{\n+\tint tun = -1;\n+\n+\tif (json_is_integer(jtun))\n+\t\ttun = (int)json_integer_value(jtun);\n+\telse if (json_is_real(jtun))\n+\t\ttun = (int)json_real_value(jtun);\n+\telse if (json_is_string(jtun)) {\n+\t\tconst char *mode = json_string_value(jtun);\n+\n+\t\tif (match_strkey(mode, \"FLEX_TUNNEL_MODE_SINGLE\"))\n+\t\t\ttun = FLEX_TUNNEL_MODE_SINGLE;\n+\t\telse if (match_strkey(mode, \"FLEX_TUNNEL_MODE_OUTER\"))\n+\t\t\ttun = FLEX_TUNNEL_MODE_OUTER;\n+\t\telse if (match_strkey(mode, \"FLEX_TUNNEL_MODE_INNER\"))\n+\t\t\ttun = FLEX_TUNNEL_MODE_INNER;\n+\t\telse if (match_strkey(mode, \"FLEX_TUNNEL_MODE_MULTI\"))\n+\t\t\ttun = FLEX_TUNNEL_MODE_MULTI;\n+\t\telse if (match_strkey(mode, \"FLEX_TUNNEL_MODE_TUNNEL\"))\n+\t\t\ttun = FLEX_TUNNEL_MODE_TUNNEL;\n+\t\telse\n+\t\t\treturn -EINVAL;\n+\t} else\n+\t\treturn -EINVAL;\n+\t*tunnel = (enum rte_flow_item_flex_tunnel_mode)tun;\n+\treturn 0;\n+}\n+\n+static int\n+flex_field_parse(json_t *jfld, struct rte_flow_item_flex_field *fld)\n+{\n+\tconst char *key;\n+\tjson_t *je;\n+\n+#define FLEX_FIELD_GET(fm, t) \\\n+do {                  \\\n+\tif (!strncmp(key, # fm, strlen(# fm))) { \\\n+\t\tif (json_is_real(je))   \\\n+\t\t\tfld->fm = (t) json_real_value(je); \\\n+\t\telse if (json_is_integer(je))   \\\n+\t\t\tfld->fm = (t) json_integer_value(je); \\\n+\t\telse   \\\n+\t\t\treturn -EINVAL; \\\n+\t}         \\\n+} while (0)\n+\n+\tjson_object_foreach(jfld, key, je) {\n+\t\tFLEX_FIELD_GET(field_size, uint32_t);\n+\t\tFLEX_FIELD_GET(field_base, int32_t);\n+\t\tFLEX_FIELD_GET(offset_base, uint32_t);\n+\t\tFLEX_FIELD_GET(offset_mask, uint32_t);\n+\t\tFLEX_FIELD_GET(offset_shift, int32_t);\n+\t\tFLEX_FIELD_GET(field_id, uint16_t);\n+\t\tif (match_strkey(key, \"field_mode\")) {\n+\t\t\tconst char *mode;\n+\t\t\tif (!json_is_string(je))\n+\t\t\t\treturn -EINVAL;\n+\t\t\tmode = json_string_value(je);\n+\t\t\tif (match_strkey(mode, \"FIELD_MODE_DUMMY\"))\n+\t\t\t\tfld->field_mode = FIELD_MODE_DUMMY;\n+\t\t\telse if (match_strkey(mode, \"FIELD_MODE_FIXED\"))\n+\t\t\t\tfld->field_mode = FIELD_MODE_FIXED;\n+\t\t\telse if (match_strkey(mode, \"FIELD_MODE_OFFSET\"))\n+\t\t\t\tfld->field_mode = FIELD_MODE_OFFSET;\n+\t\t\telse if (match_strkey(mode, \"FIELD_MODE_BITMASK\"))\n+\t\t\t\tfld->field_mode = FIELD_MODE_BITMASK;\n+\t\t\telse\n+\t\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+enum flex_link_type {\n+\tFLEX_LINK_IN = 0,\n+\tFLEX_LINK_OUT = 1\n+};\n+\n+static int\n+flex_link_item_parse(const char *src, struct rte_flow_item *item)\n+{\n+#define  FLEX_PARSE_DATA_SIZE 1024\n+\n+\tint ret;\n+\tuint8_t *ptr, data[FLEX_PARSE_DATA_SIZE] = {0,};\n+\tchar flow_rule[256];\n+\tstruct rte_flow_attr *attr;\n+\tstruct rte_flow_item *pattern;\n+\tstruct rte_flow_action *actions;\n+\n+\tsprintf(flow_rule, \"flow create 0 pattern %s / end\", src);\n+\tsrc = flow_rule;\n+\tret = flow_parse(src, (void *)data, sizeof(data),\n+\t\t\t &attr, &pattern, &actions);\n+\tif (ret)\n+\t\treturn ret;\n+\titem->type = pattern->type;\n+\tif (pattern->spec) {\n+\t\tptr = (void *)(uintptr_t)item->spec;\n+\t\tmemcpy(ptr, pattern->spec, FLEX_MAX_FLOW_PATTERN_LENGTH);\n+\t} else {\n+\t\titem->spec = NULL;\n+\t}\n+\tif (pattern->mask) {\n+\t\tptr = (void *)(uintptr_t)item->mask;\n+\t\tmemcpy(ptr, pattern->mask, FLEX_MAX_FLOW_PATTERN_LENGTH);\n+\t} else {\n+\t\titem->mask = NULL;\n+\t}\n+\tif (pattern->last) {\n+\t\tptr = (void *)(uintptr_t)item->last;\n+\t\tmemcpy(ptr, pattern->last, FLEX_MAX_FLOW_PATTERN_LENGTH);\n+\t} else {\n+\t\titem->last = NULL;\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+flex_link_parse(json_t *jobj, struct rte_flow_item_flex_link *link,\n+\t\tenum flex_link_type link_type)\n+{\n+\tconst char *key;\n+\tjson_t *je;\n+\tint ret;\n+\tjson_object_foreach(jobj, key, je) {\n+\t\tif (match_strkey(key, \"item\")) {\n+\t\t\tif (!json_is_string(je))\n+\t\t\t\treturn -EINVAL;\n+\t\t\tret = flex_link_item_parse(json_string_value(je),\n+\t\t\t\t\t\t   &link->item);\n+\t\t\tif (ret)\n+\t\t\t\treturn -EINVAL;\n+\t\t\tif (link_type == FLEX_LINK_IN) {\n+\t\t\t\tif (!link->item.spec || !link->item.mask)\n+\t\t\t\t\treturn -EINVAL;\n+\t\t\t\tif (link->item.last)\n+\t\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\t\tif (match_strkey(key, \"next\")) {\n+\t\t\tif (json_is_integer(je))\n+\t\t\t\tlink->next = (typeof(link->next))\n+\t\t\t\t\t     json_integer_value(je);\n+\t\t\telse if (json_is_real(je))\n+\t\t\t\tlink->next = (typeof(link->next))\n+\t\t\t\t\t     json_real_value(je);\n+\t\t\telse\n+\t\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static int flex_item_config(json_t *jroot,\n+\t\t\t    struct rte_flow_item_flex_conf *flex_conf)\n+{\n+\tconst char *key;\n+\tjson_t *jobj = NULL;\n+\tint ret = 0;\n+\n+\tjson_object_foreach(jroot, key, jobj) {\n+\t\tif (match_strkey(key, \"tunnel\")) {\n+\t\t\tret = flex_tunnel_parse(jobj, &flex_conf->tunnel);\n+\t\t\tif (ret) {\n+\t\t\t\tprintf(\"Can't parse tunnel value\\n\");\n+\t\t\t\tgoto out;\n+\t\t\t}\n+\t\t} else if (match_strkey(key, \"next_header\")) {\n+\t\t\tret = flex_field_parse(jobj, &flex_conf->next_header);\n+\t\t\tif (ret) {\n+\t\t\t\tprintf(\"Can't parse next_header field\\n\");\n+\t\t\t\tgoto out;\n+\t\t\t}\n+\t\t} else if (match_strkey(key, \"next_protocol\")) {\n+\t\t\tret = flex_field_parse(jobj,\n+\t\t\t\t\t       &flex_conf->next_protocol);\n+\t\t\tif (ret) {\n+\t\t\t\tprintf(\"Can't parse next_protocol field\\n\");\n+\t\t\t\tgoto out;\n+\t\t\t}\n+\t\t} else if (match_strkey(key, \"sample_data\")) {\n+\t\t\tjson_t *ji;\n+\t\t\tuint32_t i, size = json_array_size(jobj);\n+\t\t\tfor (i = 0; i < size; i++) {\n+\t\t\t\tji = json_array_get(jobj, i);\n+\t\t\t\tret = flex_field_parse\n+\t\t\t\t\t(ji, flex_conf->sample_data + i);\n+\t\t\t\tif (ret) {\n+\t\t\t\t\tprintf(\"Can't parse sample_data field(s)\\n\");\n+\t\t\t\t\tgoto out;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tflex_conf->nb_samples = size;\n+\t\t} else if (match_strkey(key, \"input_link\")) {\n+\t\t\tjson_t *ji;\n+\t\t\tuint32_t i, size = json_array_size(jobj);\n+\t\t\tfor (i = 0; i < size; i++) {\n+\t\t\t\tji = json_array_get(jobj, i);\n+\t\t\t\tret = flex_link_parse(ji,\n+\t\t\t\t\t\t      flex_conf->input_link + i,\n+\t\t\t\t\t\t      FLEX_LINK_IN);\n+\t\t\t\tif (ret) {\n+\t\t\t\t\tprintf(\"Can't parse input_link(s)\\n\");\n+\t\t\t\t\tgoto out;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tflex_conf->nb_inputs = size;\n+\t\t} else if (match_strkey(key, \"output_link\")) {\n+\t\t\tjson_t *ji;\n+\t\t\tuint32_t i, size = json_array_size(jobj);\n+\t\t\tfor (i = 0; i < size; i++) {\n+\t\t\t\tji = json_array_get(jobj, i);\n+\t\t\t\tret = flex_link_parse\n+\t\t\t\t\t(ji, flex_conf->output_link + i,\n+\t\t\t\t\t FLEX_LINK_OUT);\n+\t\t\t\tif (ret) {\n+\t\t\t\t\tprintf(\"Can't parse output_link(s)\\n\");\n+\t\t\t\t\tgoto out;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tflex_conf->nb_outputs = size;\n+\t\t}\n+\t}\n+out:\n+\treturn ret;\n+}\n+\n+static struct flex_item *\n+flex_item_init(void)\n+{\n+\tsize_t base_size, samples_size, links_size, spec_size;\n+\tstruct rte_flow_item_flex_conf *conf;\n+\tstruct flex_item *fp;\n+\tuint8_t (*pattern)[FLEX_MAX_FLOW_PATTERN_LENGTH];\n+\tint i;\n+\n+\tbase_size = RTE_ALIGN(sizeof(*conf), sizeof(uintptr_t));\n+\tsamples_size = RTE_ALIGN(FLEX_ITEM_MAX_SAMPLES_NUM *\n+\t\t\t\t sizeof(conf->sample_data[0]),\n+\t\t\t\t sizeof(uintptr_t));\n+\tlinks_size = RTE_ALIGN(FLEX_ITEM_MAX_LINKS_NUM *\n+\t\t\t       sizeof(conf->input_link[0]),\n+\t\t\t       sizeof(uintptr_t));\n+\t/* spec & mask for all input links */\n+\tspec_size = 2 * FLEX_MAX_FLOW_PATTERN_LENGTH * FLEX_ITEM_MAX_LINKS_NUM;\n+\tfp = calloc(1, base_size + samples_size + 2 * links_size + spec_size);\n+\tif (fp == NULL) {\n+\t\tprintf(\"Can't allocate memory for flex item\\n\");\n+\t\treturn NULL;\n+\t}\n+\tconf = &fp->flex_conf;\n+\tconf->sample_data = (typeof(conf->sample_data))\n+\t\t\t    ((uint8_t *)fp + base_size);\n+\tconf->input_link = (typeof(conf->input_link))\n+\t\t\t   ((uint8_t *)conf->sample_data + samples_size);\n+\tconf->output_link = (typeof(conf->output_link))\n+\t\t\t    ((uint8_t *)conf->input_link + links_size);\n+\tpattern = (typeof(pattern))((uint8_t *)conf->output_link + links_size);\n+\tfor (i = 0; i < FLEX_ITEM_MAX_LINKS_NUM; i++) {\n+\t\tstruct rte_flow_item_flex_link *in = conf->input_link + i;\n+\t\tin->item.spec = pattern++;\n+\t\tin->item.mask = pattern++;\n+\t}\n+\treturn fp;\n+}\n+\n+static int\n+flex_item_build_config(struct flex_item *fp, const char *filename)\n+{\n+\tint ret;\n+\tjson_error_t json_error;\n+\tjson_t *jroot = json_load_file(filename, 0, &json_error);\n+\n+\tif (!jroot) {\n+\t\tprintf(\"Bad JSON file \\\"%s\\\": %s\\n\", filename, json_error.text);\n+\t\treturn -1;\n+\t}\n+\tret = flex_item_config(jroot, &fp->flex_conf);\n+\tjson_decref(jroot);\n+\treturn ret;\n+}\n+\n+void\n+flex_item_create(portid_t port_id, uint16_t flex_id, const char *filename)\n+{\n+\tstruct rte_flow_error flow_error;\n+\tstruct flex_item *fp = flex_parser_fetch(port_id, flex_id);\n+\tint ret;\n+\n+\tif (fp == FLEX_PARSER_ERR) {\n+\t\tprintf(\"Bad parameters: port_id=%u flex_id=%u\\n\",\n+\t\t       port_id, flex_id);\n+\t\treturn;\n+\t}\n+\tif (fp) {\n+\t\tprintf(\"port-%u: flex item #%u is already in use\\n\",\n+\t\t       port_id, flex_id);\n+\t\treturn;\n+\t}\n+\tfp = flex_item_init();\n+\tif (!fp) {\n+\t\tprintf(\"Could not allocate flex item\\n\");\n+\t\tgoto out;\n+\t}\n+\tret = flex_item_build_config(fp, filename);\n+\tif (ret)\n+\t\tgoto out;\n+\tfp->flex_handle = rte_flow_flex_item_create(port_id,\n+\t\t\t\t\t\t    &fp->flex_conf,\n+\t\t\t\t\t\t    &flow_error);\n+\tif (fp->flex_handle) {\n+\t\tflex_items[port_id][flex_id] = fp;\n+\t\tprintf(\"port-%u: created flex item #%u\\n\", port_id, flex_id);\n+\t\tfp = NULL;\n+\t} else {\n+\t\tprintf(\"port-%u: flex item #%u creation failed: %s\\n\",\n+\t\t       port_id, flex_id,\n+\t\t       flow_error.message ? flow_error.message : \"\");\n+\t}\n+out:\n+\tif (fp)\n+\t\tfree(fp);\n+}\n+\n+#else /* RTE_HAS_JANSSON */\n+void flex_item_create(__rte_unused portid_t port_id,\n+\t\t      __rte_unused uint16_t flex_id,\n+\t\t      __rte_unused const char *filename)\n+{\n+\tprintf(\"no JSON library\\n\");\n+}\n+\n+void flex_item_destroy(__rte_unused portid_t port_id,\n+\t\t       __rte_unused uint16_t flex_id)\n+{\n+\tprintf(\"no JSON library\\n\");\n+}\n+#endif /* RTE_HAS_JANSSON */\n+\n+void\n+port_flex_item_flush(portid_t port_id)\n+{\n+\tuint16_t i;\n+\n+\tfor (i = 0; i < FLEX_MAX_PARSERS_NUM; i++) {\n+\t\tflex_item_destroy(port_id, i);\n+\t\tflex_items[port_id][i] = NULL;\n+\t}\n+}\n+\n+struct flex_pattern_set {\n+\tcmdline_fixed_string_t set, flex_pattern;\n+\tcmdline_fixed_string_t is_spec, mask;\n+\tcmdline_fixed_string_t spec_data, mask_data;\n+\tuint16_t id;\n+};\n+\n+static cmdline_parse_token_string_t flex_pattern_set_token =\n+\tTOKEN_STRING_INITIALIZER(struct flex_pattern_set, set, \"set\");\n+static cmdline_parse_token_string_t flex_pattern_token =\n+\tTOKEN_STRING_INITIALIZER(struct flex_pattern_set,\n+flex_pattern, \"flex_pattern\");\n+static cmdline_parse_token_string_t flex_pattern_is_token =\n+\tTOKEN_STRING_INITIALIZER(struct flex_pattern_set,\n+is_spec, \"is\");\n+static cmdline_parse_token_string_t flex_pattern_spec_token =\n+\tTOKEN_STRING_INITIALIZER(struct flex_pattern_set,\n+is_spec, \"spec\");\n+static cmdline_parse_token_string_t flex_pattern_mask_token =\n+\tTOKEN_STRING_INITIALIZER(struct flex_pattern_set, mask, \"mask\");\n+static cmdline_parse_token_string_t flex_pattern_spec_data_token =\n+\tTOKEN_STRING_INITIALIZER(struct flex_pattern_set, spec_data, NULL);\n+static cmdline_parse_token_string_t flex_pattern_mask_data_token =\n+\tTOKEN_STRING_INITIALIZER(struct flex_pattern_set, mask_data, NULL);\n+static cmdline_parse_token_num_t flex_pattern_id_token =\n+\tTOKEN_NUM_INITIALIZER(struct flex_pattern_set, id, RTE_UINT16);\n+\n+/*\n+ * flex pattern data - spec or mask is a string representation of byte array\n+ * in hexadecimal format. Each byte in data string must have 2 characters:\n+ * 0x15 - \"15\"\n+ * 0x1  - \"01\"\n+ * Bytes in data array are in network order.\n+ */\n+static uint32_t\n+flex_pattern_data(const char *str, uint8_t *data)\n+{\n+\tuint32_t i, len = strlen(str);\n+\tchar b[3], *endptr;\n+\n+\tif (len & 01)\n+\t\treturn 0;\n+\tlen /= 2;\n+\tif (len >= FLEX_MAX_FLOW_PATTERN_LENGTH)\n+\t\treturn 0;\n+\tfor (i = 0, b[2] = '\\0'; i < len; i++) {\n+\t\tb[0] = str[2 * i];\n+\t\tb[1] = str[2 * i + 1];\n+\t\tdata[i] = strtoul(b, &endptr, 16);\n+\t\tif (endptr != &b[2])\n+\t\t\treturn 0;\n+\t}\n+\treturn len;\n+}\n+\n+static void\n+flex_pattern_parsed_fn(void *parsed_result,\n+\t\t       __rte_unused struct cmdline *cl,\n+\t\t       __rte_unused void *data)\n+{\n+\tstruct flex_pattern_set *res = parsed_result;\n+\tstruct flex_pattern *fp;\n+\tbool full_spec;\n+\n+\tif (res->id >= FLEX_MAX_PATTERNS_NUM) {\n+\t\tprintf(\"Bad flex pattern id\\n\");\n+\t\treturn;\n+\t}\n+\tfp = flex_patterns + res->id;\n+\tmemset(fp->spec_pattern, 0, sizeof(fp->spec_pattern));\n+\tmemset(fp->mask_pattern, 0, sizeof(fp->mask_pattern));\n+\tfp->spec.length = flex_pattern_data(res->spec_data, fp->spec_pattern);\n+\tif (!fp->spec.length) {\n+\t\tprintf(\"Bad flex pattern spec\\n\");\n+\t\treturn;\n+\t}\n+\tfull_spec = strncmp(res->is_spec, \"spec\", strlen(\"spec\")) == 0;\n+\tif (full_spec) {\n+\t\tfp->mask.length = flex_pattern_data(res->mask_data,\n+\t\t\t\t\t\t    fp->mask_pattern);\n+\t\tif (!fp->mask.length) {\n+\t\t\tprintf(\"Bad flex pattern mask\\n\");\n+\t\t\treturn;\n+\t\t}\n+\t} else {\n+\t\tmemset(fp->mask_pattern, 0xFF, fp->spec.length);\n+\t\tfp->mask.length = fp->spec.length;\n+\t}\n+\tif (fp->mask.length != fp->spec.length) {\n+\t\tprintf(\"Spec length do not match mask length\\n\");\n+\t\treturn;\n+\t}\n+\tfp->spec.pattern = fp->spec_pattern;\n+\tfp->mask.pattern = fp->mask_pattern;\n+\tprintf(\"created pattern #%u\\n\", res->id);\n+}\n+\n+cmdline_parse_inst_t cmd_set_flex_is_pattern = {\n+\t.f = flex_pattern_parsed_fn,\n+\t.data = NULL,\n+\t.help_str = \"set flex_pattern <id> is <spec_data>\",\n+\t.tokens = {\n+\t\t(void *)&flex_pattern_set_token,\n+\t\t(void *)&flex_pattern_token,\n+\t\t(void *)&flex_pattern_id_token,\n+\t\t(void *)&flex_pattern_is_token,\n+\t\t(void *)&flex_pattern_spec_data_token,\n+\t\tNULL,\n+\t}\n+};\n+\n+cmdline_parse_inst_t cmd_set_flex_spec_pattern = {\n+\t.f = flex_pattern_parsed_fn,\n+\t.data = NULL,\n+\t.help_str = \"set flex_pattern <id> spec <spec_data> mask <mask_data>\",\n+\t.tokens = {\n+\t\t(void *)&flex_pattern_set_token,\n+\t\t(void *)&flex_pattern_token,\n+\t\t(void *)&flex_pattern_id_token,\n+\t\t(void *)&flex_pattern_spec_token,\n+\t\t(void *)&flex_pattern_spec_data_token,\n+\t\t(void *)&flex_pattern_mask_token,\n+\t\t(void *)&flex_pattern_mask_data_token,\n+\t\tNULL,\n+\t}\n+};\ndiff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c\nindex 88354ccab9..3221f6e1aa 100644\n--- a/app/test-pmd/cmdline.c\n+++ b/app/test-pmd/cmdline.c\n@@ -17861,6 +17861,8 @@ cmdline_parse_ctx_t main_ctx[] = {\n \t(cmdline_parse_inst_t *)&cmd_show_fec_mode,\n \t(cmdline_parse_inst_t *)&cmd_set_fec_mode,\n \t(cmdline_parse_inst_t *)&cmd_show_capability,\n+\t(cmdline_parse_inst_t *)&cmd_set_flex_is_pattern,\n+\t(cmdline_parse_inst_t *)&cmd_set_flex_spec_pattern,\n \tNULL,\n };\n \ndiff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c\nindex cd640b9b7a..5437975837 100644\n--- a/app/test-pmd/cmdline_flow.c\n+++ b/app/test-pmd/cmdline_flow.c\n@@ -54,6 +54,8 @@ enum index {\n \tCOMMON_PRIORITY_LEVEL,\n \tCOMMON_INDIRECT_ACTION_ID,\n \tCOMMON_POLICY_ID,\n+\tCOMMON_FLEX_HANDLE,\n+\tCOMMON_FLEX_TOKEN,\n \n \t/* TOP-level command. */\n \tADD,\n@@ -81,6 +83,12 @@ enum index {\n \tAGED,\n \tISOLATE,\n \tTUNNEL,\n+\tFLEX,\n+\n+\t/* Flex arguments */\n+\tFLEX_ITEM_INIT,\n+\tFLEX_ITEM_CREATE,\n+\tFLEX_ITEM_DESTROY,\n \n \t/* Tunnel arguments. */\n \tTUNNEL_CREATE,\n@@ -310,6 +318,9 @@ enum index {\n \tITEM_PORT_REPRESENTOR_PORT_ID,\n \tITEM_REPRESENTED_PORT,\n \tITEM_REPRESENTED_PORT_ETHDEV_PORT_ID,\n+\tITEM_FLEX,\n+\tITEM_FLEX_ITEM_HANDLE,\n+\tITEM_FLEX_PATTERN_HANDLE,\n \n \t/* Validate/create actions. */\n \tACTIONS,\n@@ -860,6 +871,11 @@ struct buffer {\n \t\tstruct {\n \t\t\tuint32_t policy_id;\n \t\t} policy;/**< Policy arguments. */\n+\t\tstruct {\n+\t\t\tuint16_t token;\n+\t\t\tuintptr_t uintptr;\n+\t\t\tchar filename[128];\n+\t\t} flex; /**< Flex arguments*/\n \t} args; /**< Command arguments. */\n };\n \n@@ -887,6 +903,13 @@ struct parse_action_priv {\n \t\t.size = s, \\\n \t})\n \n+static const enum index next_flex_item[] = {\n+\tFLEX_ITEM_INIT,\n+\tFLEX_ITEM_CREATE,\n+\tFLEX_ITEM_DESTROY,\n+\tZERO,\n+};\n+\n static const enum index next_ia_create_attr[] = {\n \tINDIRECT_ACTION_CREATE_ID,\n \tINDIRECT_ACTION_INGRESS,\n@@ -1018,6 +1041,7 @@ static const enum index next_item[] = {\n \tITEM_CONNTRACK,\n \tITEM_PORT_REPRESENTOR,\n \tITEM_REPRESENTED_PORT,\n+\tITEM_FLEX,\n \tEND_SET,\n \tZERO,\n };\n@@ -1398,6 +1422,13 @@ static const enum index item_represented_port[] = {\n \tZERO,\n };\n \n+static const enum index item_flex[] = {\n+\tITEM_FLEX_PATTERN_HANDLE,\n+\tITEM_FLEX_ITEM_HANDLE,\n+\tITEM_NEXT,\n+\tZERO,\n+};\n+\n static const enum index next_action[] = {\n \tACTION_END,\n \tACTION_VOID,\n@@ -1768,6 +1799,9 @@ static int parse_set_sample_action(struct context *, const struct token *,\n static int parse_set_init(struct context *, const struct token *,\n \t\t\t  const char *, unsigned int,\n \t\t\t  void *, unsigned int);\n+static int\n+parse_flex_handle(struct context *, const struct token *,\n+\t\t  const char *, unsigned int, void *, unsigned int);\n static int parse_init(struct context *, const struct token *,\n \t\t      const char *, unsigned int,\n \t\t      void *, unsigned int);\n@@ -1884,6 +1918,8 @@ static int parse_isolate(struct context *, const struct token *,\n static int parse_tunnel(struct context *, const struct token *,\n \t\t\tconst char *, unsigned int,\n \t\t\tvoid *, unsigned int);\n+static int parse_flex(struct context *, const struct token *,\n+\t\t      const char *, unsigned int, void *, unsigned int);\n static int parse_int(struct context *, const struct token *,\n \t\t     const char *, unsigned int,\n \t\t     void *, unsigned int);\n@@ -2084,6 +2120,20 @@ static const struct token token_list[] = {\n \t\t.call = parse_int,\n \t\t.comp = comp_none,\n \t},\n+\t[COMMON_FLEX_TOKEN] = {\n+\t\t.name = \"{flex token}\",\n+\t\t.type = \"flex token\",\n+\t\t.help = \"flex token\",\n+\t\t.call = parse_int,\n+\t\t.comp = comp_none,\n+\t},\n+\t[COMMON_FLEX_HANDLE] = {\n+\t\t.name = \"{flex handle}\",\n+\t\t.type = \"FLEX HANDLE\",\n+\t\t.help = \"fill flex item data\",\n+\t\t.call = parse_flex_handle,\n+\t\t.comp = comp_none,\n+\t},\n \t/* Top-level command. */\n \t[FLOW] = {\n \t\t.name = \"flow\",\n@@ -2100,7 +2150,8 @@ static const struct token token_list[] = {\n \t\t\t      AGED,\n \t\t\t      QUERY,\n \t\t\t      ISOLATE,\n-\t\t\t      TUNNEL)),\n+\t\t\t      TUNNEL,\n+\t\t\t      FLEX)),\n \t\t.call = parse_init,\n \t},\n \t/* Top-level command. */\n@@ -2212,6 +2263,41 @@ static const struct token token_list[] = {\n \t\t\t     ARGS_ENTRY(struct buffer, port)),\n \t\t.call = parse_isolate,\n \t},\n+\t[FLEX] = {\n+\t\t.name = \"flex_item\",\n+\t\t.help = \"flex item API\",\n+\t\t.next = NEXT(next_flex_item),\n+\t\t.call = parse_flex,\n+\t},\n+\t[FLEX_ITEM_INIT] = {\n+\t\t.name = \"init\",\n+\t\t.help = \"flex item init\",\n+\t\t.args = ARGS(ARGS_ENTRY(struct buffer, args.flex.token),\n+\t\t\t     ARGS_ENTRY(struct buffer, port)),\n+\t\t.next = NEXT(NEXT_ENTRY(COMMON_FLEX_TOKEN),\n+\t\t\t     NEXT_ENTRY(COMMON_PORT_ID)),\n+\t\t.call = parse_flex\n+\t},\n+\t[FLEX_ITEM_CREATE] = {\n+\t\t.name = \"create\",\n+\t\t.help = \"flex item create\",\n+\t\t.args = ARGS(ARGS_ENTRY(struct buffer, args.flex.filename),\n+\t\t\t     ARGS_ENTRY(struct buffer, args.flex.token),\n+\t\t\t     ARGS_ENTRY(struct buffer, port)),\n+\t\t.next = NEXT(NEXT_ENTRY(COMMON_FILE_PATH),\n+\t\t\t     NEXT_ENTRY(COMMON_FLEX_TOKEN),\n+\t\t\t     NEXT_ENTRY(COMMON_PORT_ID)),\n+\t\t.call = parse_flex\n+\t},\n+\t[FLEX_ITEM_DESTROY] = {\n+\t\t.name = \"destroy\",\n+\t\t.help = \"flex item destroy\",\n+\t\t.args = ARGS(ARGS_ENTRY(struct buffer, args.flex.token),\n+\t\t\t     ARGS_ENTRY(struct buffer, port)),\n+\t\t.next = NEXT(NEXT_ENTRY(COMMON_FLEX_TOKEN),\n+\t\t\t     NEXT_ENTRY(COMMON_PORT_ID)),\n+\t\t.call = parse_flex\n+\t},\n \t[TUNNEL] = {\n \t\t.name = \"tunnel\",\n \t\t.help = \"new tunnel API\",\n@@ -3682,6 +3768,27 @@ static const struct token token_list[] = {\n \t\t\t     item_param),\n \t\t.args = ARGS(ARGS_ENTRY(struct rte_flow_item_ethdev, port_id)),\n \t},\n+\t[ITEM_FLEX] = {\n+\t\t.name = \"flex\",\n+\t\t.help = \"match flex header\",\n+\t\t.priv = PRIV_ITEM(FLEX, sizeof(struct rte_flow_item_flex)),\n+\t\t.next = NEXT(item_flex),\n+\t\t.call = parse_vc,\n+\t},\n+\t[ITEM_FLEX_ITEM_HANDLE] = {\n+\t\t.name = \"item\",\n+\t\t.help = \"flex item handle\",\n+\t\t.next = NEXT(item_flex, NEXT_ENTRY(COMMON_FLEX_HANDLE),\n+\t\t\t     NEXT_ENTRY(ITEM_PARAM_IS)),\n+\t\t.args = ARGS(ARGS_ENTRY(struct rte_flow_item_flex, handle)),\n+\t},\n+\t[ITEM_FLEX_PATTERN_HANDLE] = {\n+\t\t.name = \"pattern\",\n+\t\t.help = \"flex pattern handle\",\n+\t\t.next = NEXT(item_flex, NEXT_ENTRY(COMMON_FLEX_HANDLE),\n+\t\t\t     NEXT_ENTRY(ITEM_PARAM_IS)),\n+\t\t.args = ARGS(ARGS_ENTRY(struct rte_flow_item_flex, pattern)),\n+\t},\n \t/* Validate/create actions. */\n \t[ACTIONS] = {\n \t\t.name = \"actions\",\n@@ -7113,6 +7220,43 @@ parse_isolate(struct context *ctx, const struct token *token,\n \treturn len;\n }\n \n+static int\n+parse_flex(struct context *ctx, const struct token *token,\n+\t     const char *str, unsigned int len,\n+\t     void *buf, unsigned int size)\n+{\n+\tstruct buffer *out = buf;\n+\n+\t/* Token name must match. */\n+\tif (parse_default(ctx, token, str, len, NULL, 0) < 0)\n+\t\treturn -1;\n+\t/* Nothing else to do if there is no buffer. */\n+\tif (!out)\n+\t\treturn len;\n+\tif (out->command == ZERO) {\n+\t\tif (ctx->curr != FLEX)\n+\t\t\treturn -1;\n+\t\tif (sizeof(*out) > size)\n+\t\t\treturn -1;\n+\t\tout->command = ctx->curr;\n+\t\tctx->objdata = 0;\n+\t\tctx->object = out;\n+\t\tctx->objmask = NULL;\n+\t} else {\n+\t\tswitch (ctx->curr) {\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\tcase FLEX_ITEM_INIT:\n+\t\tcase FLEX_ITEM_CREATE:\n+\t\tcase FLEX_ITEM_DESTROY:\n+\t\t\tout->command = ctx->curr;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn len;\n+}\n+\n static int\n parse_tunnel(struct context *ctx, const struct token *token,\n \t     const char *str, unsigned int len,\n@@ -7778,6 +7922,71 @@ parse_set_init(struct context *ctx, const struct token *token,\n \treturn len;\n }\n \n+/*\n+ * Replace testpmd handles in a flex flow item with real values.\n+ */\n+static int\n+parse_flex_handle(struct context *ctx, const struct token *token,\n+\t\t  const char *str, unsigned int len,\n+\t\t  void *buf, unsigned int size)\n+{\n+\tstruct rte_flow_item_flex *spec, *mask;\n+\tconst struct rte_flow_item_flex *src_spec, *src_mask;\n+\tconst struct arg *arg = pop_args(ctx);\n+\tuint32_t offset;\n+\tuint16_t handle;\n+\tint ret;\n+\n+\tif (!arg) {\n+\t\tprintf(\"Bad environment\\n\");\n+\t\treturn -1;\n+\t}\n+\toffset = arg->offset;\n+\tpush_args(ctx, arg);\n+\tret = parse_int(ctx, token, str, len, buf, size);\n+\tif (ret <= 0 || !ctx->object)\n+\t\treturn ret;\n+\tif (ctx->port >= RTE_MAX_ETHPORTS) {\n+\t\tprintf(\"Bad port\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (offset == offsetof(struct rte_flow_item_flex, handle)) {\n+\t\tconst struct flex_item *fp;\n+\t\tstruct rte_flow_item_flex *item_flex = ctx->object;\n+\t\thandle = (uint16_t)(uintptr_t)item_flex->handle;\n+\t\tif (handle >= FLEX_MAX_PARSERS_NUM) {\n+\t\t\tprintf(\"Bad flex item handle\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tfp = flex_items[ctx->port][handle];\n+\t\tif (!fp) {\n+\t\t\tprintf(\"Bad flex item handle\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\titem_flex->handle = fp->flex_handle;\n+\t} else if (offset == offsetof(struct rte_flow_item_flex, pattern)) {\n+\t\thandle = (uint16_t)(uintptr_t)\n+\t\t\t((struct rte_flow_item_flex *)ctx->object)->pattern;\n+\t\tif (handle >= FLEX_MAX_PATTERNS_NUM) {\n+\t\t\tprintf(\"Bad pattern handle\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tsrc_spec = &flex_patterns[handle].spec;\n+\t\tsrc_mask = &flex_patterns[handle].mask;\n+\t\tspec = ctx->object;\n+\t\tmask = spec + 2; /* spec, last, mask */\n+\t\t/* fill flow rule spec and mask parameters */\n+\t\tspec->length = src_spec->length;\n+\t\tspec->pattern = src_spec->pattern;\n+\t\tmask->length = src_mask->length;\n+\t\tmask->pattern = src_mask->pattern;\n+\t} else {\n+\t\tprintf(\"Bad arguments - unknown flex item offset\\n\");\n+\t\treturn -1;\n+\t}\n+\treturn ret;\n+}\n+\n /** No completion. */\n static int\n comp_none(struct context *ctx, const struct token *token,\n@@ -8305,6 +8514,13 @@ cmd_flow_parsed(const struct buffer *in)\n \t\tport_meter_policy_add(in->port, in->args.policy.policy_id,\n \t\t\t\t\tin->args.vc.actions);\n \t\tbreak;\n+\tcase FLEX_ITEM_CREATE:\n+\t\tflex_item_create(in->port, in->args.flex.token,\n+\t\t\t\t in->args.flex.filename);\n+\t\tbreak;\n+\tcase FLEX_ITEM_DESTROY:\n+\t\tflex_item_destroy(in->port, in->args.flex.token);\n+\t\tbreak;\n \tdefault:\n \t\tbreak;\n \t}\n@@ -8760,6 +8976,11 @@ cmd_set_raw_parsed(const struct buffer *in)\n \t\tcase RTE_FLOW_ITEM_TYPE_PFCP:\n \t\t\tsize = sizeof(struct rte_flow_item_pfcp);\n \t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_FLEX:\n+\t\t\tsize = item->spec ?\n+\t\t\t\t((const struct rte_flow_item_flex *)\n+\t\t\t\titem->spec)->length : 0;\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\tfprintf(stderr, \"Error - Not supported item\\n\");\n \t\t\tgoto error;\ndiff --git a/app/test-pmd/meson.build b/app/test-pmd/meson.build\nindex 98f3289bdf..201bed013f 100644\n--- a/app/test-pmd/meson.build\n+++ b/app/test-pmd/meson.build\n@@ -10,6 +10,7 @@ sources = files(\n         'cmdline_flow.c',\n         'cmdline_mtr.c',\n         'cmdline_tm.c',\n+\t'cmd_flex_item.c',\n         'config.c',\n         'csumonly.c',\n         'flowgen.c',\n@@ -61,3 +62,8 @@ if dpdk_conf.has('RTE_LIB_BPF')\n     sources += files('bpf_cmd.c')\n     deps += 'bpf'\n endif\n+jansson_dep = dependency('jansson', required: false, method: 'pkg-config')\n+if jansson_dep.found()\n+    dpdk_conf.set('RTE_HAS_JANSSON', 1)\n+    ext_deps += jansson_dep\n+endif\ndiff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c\nindex de7a8c2955..af0e79fe6d 100644\n--- a/app/test-pmd/testpmd.c\n+++ b/app/test-pmd/testpmd.c\n@@ -3118,6 +3118,7 @@ close_port(portid_t pid)\n \n \t\tif (is_proc_primary()) {\n \t\t\tport_flow_flush(pi);\n+\t\t\tport_flex_item_flush(pi);\n \t\t\trte_eth_dev_close(pi);\n \t\t}\n \n@@ -4223,7 +4224,6 @@ main(int argc, char** argv)\n \t\trte_stats_bitrate_reg(bitrate_data);\n \t}\n #endif\n-\n #ifdef RTE_LIB_CMDLINE\n \tif (strlen(cmdline_filename) != 0)\n \t\tcmdline_read_from_file(cmdline_filename);\ndiff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h\nindex 81be754605..e3995d24ab 100644\n--- a/app/test-pmd/testpmd.h\n+++ b/app/test-pmd/testpmd.h\n@@ -14,6 +14,9 @@\n #include <rte_os_shim.h>\n #include <cmdline.h>\n #include <sys/queue.h>\n+#ifdef RTE_HAS_JANSSON\n+#include <jansson.h>\n+#endif\n \n #define RTE_PORT_ALL            (~(portid_t)0x0)\n \n@@ -295,6 +298,27 @@ struct fwd_engine {\n \tpacket_fwd_t     packet_fwd;     /**< Mandatory. */\n };\n \n+#define FLEX_ITEM_MAX_SAMPLES_NUM 16\n+#define FLEX_ITEM_MAX_LINKS_NUM 16\n+#define FLEX_MAX_FLOW_PATTERN_LENGTH 64\n+#define FLEX_MAX_PARSERS_NUM 8\n+#define FLEX_MAX_PATTERNS_NUM 64\n+#define FLEX_PARSER_ERR ((struct flex_item *)-1)\n+\n+struct flex_item {\n+\tstruct rte_flow_item_flex_conf flex_conf;\n+\tstruct rte_flow_item_flex_handle *flex_handle;\n+\tuint32_t flex_id;\n+};\n+\n+struct flex_pattern {\n+\tstruct rte_flow_item_flex spec, mask;\n+\tuint8_t spec_pattern[FLEX_MAX_FLOW_PATTERN_LENGTH];\n+\tuint8_t mask_pattern[FLEX_MAX_FLOW_PATTERN_LENGTH];\n+};\n+extern struct flex_item *flex_items[RTE_MAX_ETHPORTS][FLEX_MAX_PARSERS_NUM];\n+extern struct flex_pattern flex_patterns[FLEX_MAX_PATTERNS_NUM];\n+\n #define BURST_TX_WAIT_US 1\n #define BURST_TX_RETRIES 64\n \n@@ -319,6 +343,8 @@ extern struct fwd_engine * fwd_engines[]; /**< NULL terminated array. */\n extern cmdline_parse_inst_t cmd_set_raw;\n extern cmdline_parse_inst_t cmd_show_set_raw;\n extern cmdline_parse_inst_t cmd_show_set_raw_all;\n+extern cmdline_parse_inst_t cmd_set_flex_is_pattern;\n+extern cmdline_parse_inst_t cmd_set_flex_spec_pattern;\n \n extern uint16_t mempool_flags;\n \n@@ -1046,6 +1072,10 @@ uint16_t tx_pkt_set_dynf(uint16_t port_id, __rte_unused uint16_t queue,\n void add_tx_dynf_callback(portid_t portid);\n void remove_tx_dynf_callback(portid_t portid);\n int update_mtu_from_frame_size(portid_t portid, uint32_t max_rx_pktlen);\n+int update_jumbo_frame_offload(portid_t portid);\n+void flex_item_create(portid_t port_id, uint16_t flex_id, const char *filename);\n+void flex_item_destroy(portid_t port_id, uint16_t flex_id);\n+void port_flex_item_flush(portid_t port_id);\n \n extern int flow_parse(const char *src, void *result, unsigned int size,\n \t\t      struct rte_flow_attr **attr,\ndiff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\nindex 22ba8f0516..6d127d9a7b 100644\n--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n@@ -5091,3 +5091,122 @@ For example to unload BPF filter from TX queue 0, port 0:\n .. code-block:: console\n \n    testpmd> bpf-unload tx 0 0\n+\n+Flex Item Functions\n+-------------------\n+\n+The following sections show functions that configure and create flex item object,\n+create flex pattern and use it in a flow rule.\n+The commands will use 20 bytes IPv4 header for examples:\n+\n+::\n+\n+   0                   1                   2                   3\n+   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n+   |  ver  |  IHL  |     TOS       |        length                 | +0\n+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n+   |       identification          | flg |    frag. offset         | +4\n+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n+   |       TTL     |  protocol     |        checksum               | +8\n+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n+   |               source IP address                               | +12\n+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n+   |              destination IP address                           | +16\n+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n+\n+\n+Create flex item\n+~~~~~~~~~~~~~~~~\n+\n+Flex item object is created by PMD according to a new header configuration. The\n+header configuration is compiled by the testpmd and stored in\n+``rte_flow_item_flex_conf`` type variable.\n+\n+::\n+\n+   # flow flex_item create <port> <flex id> <configuration file>\n+   testpmd> flow flex_item init 0 3 ipv4_flex_config.json\n+   port-0: created flex item #3\n+\n+Flex item configuration is kept in external JSON file.\n+It describes the following header elements:\n+\n+**New header length.**\n+\n+Specify whether the new header has fixed or variable length and the basic/minimal\n+header length value.\n+\n+If header length is not fixed, header location with a value that completes header\n+length calculation and scale/offset function must be added.\n+\n+Scale function depends on port hardware.\n+\n+**Next protocol.**\n+\n+Describes location in the new header that specify following network header type.\n+\n+**Flow match samples.**\n+\n+Describes locations in the new header that will be used in flow rules.\n+\n+Number of flow samples and sample maximal length depend of port hardware.\n+\n+**Input trigger.**\n+\n+Describes preceding network header configuration.\n+\n+**Output trigger.**\n+\n+Describes conditions that trigger transfer to following network header\n+\n+.. code-block:: json\n+\n+   {\n+      \"next_header\": { \"field_mode\": \"FIELD_MODE_FIXED\", \"field_size\": 20},\n+      \"next_protocol\": {\"field_size\": 8, \"field_base\": 72},\n+      \"sample_data\": [\n+         { \"field_mode\": \"FIELD_MODE_FIXED\", \"field_size\": 32, \"field_base\": 0},\n+         { \"field_mode\": \"FIELD_MODE_FIXED\", \"field_size\": 32, \"field_base\": 32},\n+         { \"field_mode\": \"FIELD_MODE_FIXED\", \"field_size\": 32, \"field_base\": 64},\n+         { \"field_mode\": \"FIELD_MODE_FIXED\", \"field_size\": 32, \"field_base\": 96}\n+      ],\n+      \"input_link\": [\n+         {\"item\": \"eth type is 0x0800\"},\n+         {\"item\": \"vlan inner_type is 0x0800\"}\n+      ],\n+      \"output_link\": [\n+         {\"item\": \"udp\", \"next\": 17},\n+         {\"item\": \"tcp\", \"next\": 6},\n+         {\"item\": \"icmp\", \"next\": 1}\n+      ]\n+   }\n+\n+\n+Flex pattern and flow rules\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Flex pattern describe parts of network header that will trigger flex flow item hit in a flow rule.\n+Flex pattern directly related to flex item samples configuration.\n+Flex pattern can be shared between ports.\n+\n+**Flex pattern and flow rule to match IPv4 version and 20 bytes length**\n+\n+::\n+\n+   # set flex_pattern <pattern_id> is <hex bytes sequence>\n+   testpmd> flow flex_item pattern 5 is 45FF\n+   created pattern #5\n+\n+   testpmd> flow create 0 ingress pattern eth / ipv4 / udp / flex item is 3 pattern is 5 / end actions mark id 1 / queue index 0 / end\n+   Flow rule #0 created\n+\n+**Flex pattern and flow rule to match packets with source address 1.2.3.4**\n+\n+::\n+\n+   testpmd> flow flex_item pattern 2 spec 45000000000000000000000001020304 mask FF0000000000000000000000FFFFFFFF\n+   created pattern #2\n+\n+   testpmd> flow create 0 ingress pattern eth / ipv4 / udp / flex item is 3 pattern is 2 / end actions mark id 1 / queue index 0 / end\n+   Flow rule #0 created\n",
    "prefixes": [
        "v8",
        "4/4"
    ]
}