get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 81065,
    "url": "https://patches.dpdk.org/api/patches/81065/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20201016085557.18884-4-getelson@nvidia.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20201016085557.18884-4-getelson@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20201016085557.18884-4-getelson@nvidia.com",
    "date": "2020-10-16T08:55:57",
    "name": "[v6,3/3] app/testpmd: add commands for tunnel offload API",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "647ecf2568e8a75a2c1c2323eba98fa4a0a9f27e",
    "submitter": {
        "id": 1882,
        "url": "https://patches.dpdk.org/api/people/1882/?format=api",
        "name": "Gregory Etelson",
        "email": "getelson@nvidia.com"
    },
    "delegate": {
        "id": 319,
        "url": "https://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20201016085557.18884-4-getelson@nvidia.com/mbox/",
    "series": [
        {
            "id": 13048,
            "url": "https://patches.dpdk.org/api/series/13048/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=13048",
            "date": "2020-10-16T08:55:54",
            "name": "Tunnel Offload API",
            "version": 6,
            "mbox": "https://patches.dpdk.org/series/13048/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/81065/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/81065/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 5DC53A04DB;\n\tFri, 16 Oct 2020 10:56:59 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 7D7881EBC5;\n\tFri, 16 Oct 2020 10:56:38 +0200 (CEST)",
            "from hqnvemgate25.nvidia.com (hqnvemgate25.nvidia.com\n [216.228.121.64]) by dpdk.org (Postfix) with ESMTP id BD0A41EBBA\n for <dev@dpdk.org>; Fri, 16 Oct 2020 10:56:35 +0200 (CEST)",
            "from hqmail.nvidia.com (Not Verified[216.228.121.13]) by\n hqnvemgate25.nvidia.com (using TLS: TLSv1.2, AES256-SHA)\n id <B5f8960150000>; Fri, 16 Oct 2020 01:55:49 -0700",
            "from nvidia.com (10.124.1.5) by HQMAIL107.nvidia.com (172.20.187.13)\n with Microsoft SMTP Server (TLS) id 15.0.1473.3;\n Fri, 16 Oct 2020 08:56:23 +0000"
        ],
        "From": "Gregory Etelson <getelson@nvidia.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<getelson@nvidia.com>, <matan@nvidia.com>, <rasland@nvidia.com>,\n <elibr@nvidia.com>, <ozsh@nvidia.com>, <ajit.khaparde@broadcom.com>,\n <asafp@nvidia.com>, Ori Kam <orika@nvidia.com>, Wenzhuo Lu\n <wenzhuo.lu@intel.com>, Beilei Xing <beilei.xing@intel.com>, \"Bernard\n Iremonger\" <bernard.iremonger@intel.com>",
        "Date": "Fri, 16 Oct 2020 11:55:57 +0300",
        "Message-ID": "<20201016085557.18884-4-getelson@nvidia.com>",
        "X-Mailer": "git-send-email 2.28.0",
        "In-Reply-To": "<20201016085557.18884-1-getelson@nvidia.com>",
        "References": "<20200625160348.26220-1-getelson@mellanox.com>\n <20201016085557.18884-1-getelson@nvidia.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "quoted-printable",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.124.1.5]",
        "X-ClientProxiedBy": "HQMAIL111.nvidia.com (172.20.187.18) To\n HQMAIL107.nvidia.com (172.20.187.13)",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1;\n t=1602838549; bh=RD7haO+bhKJ/YAd+idUQdHvD9lnYxRhn+3qtgcv+iG8=;\n h=From:To:CC:Subject:Date:Message-ID:X-Mailer:In-Reply-To:\n References:MIME-Version:Content-Transfer-Encoding:Content-Type:\n X-Originating-IP:X-ClientProxiedBy;\n b=SFxXBHhBg09YSSEckfgVuuGjBP/wlxsmnETqaFwPMB5R9VPjDGyGFhwE/1HRDRPoq\n y0XgKMPewZr+kX74W4eoZG3sHdW+H3x+5vj+OV8wBBCDUQKARIU+Kc0EedfSlc/qgW\n YrH8iVDGJL90ifnJFN1Hex4cjMKQoRW2VuxsLk2oY4lgEtfjk9LO50tgqN7JvqrAyQ\n uNSGNMYHzBe5QXP45CuFopZ82OZGDIZvo42DZmp/HrZH/NymxX0BnIeflQWGhorlf9\n xqeb7XZhmd8ckw3iWZvKb21SBnEL5U50pD3oWDkIZCYdLMypYLEIOoIEfT/h9WyieR\n t8RRg5C/fxYkQ==",
        "Subject": "[dpdk-dev] [PATCH v6 3/3] app/testpmd: add commands for tunnel\n\toffload API",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Tunnel Offload API provides hardware independent, unified model\nto offload tunneled traffic. Key model elements are:\n - apply matches to both outer and inner packet headers\n   during entire offload procedure;\n - restore outer header of partially offloaded packet;\n - model is implemented as a set of helper functions.\n\nImplementation details:\n\n* Create application tunnel:\nflow tunnel create <port> type <tunnel type>\nOn success, the command creates application tunnel object and returns\nthe tunnel descriptor. Tunnel descriptor is used in subsequent flow\ncreation commands to reference the tunnel.\n\n* Create tunnel steering flow rule:\ntunnel_set <tunnel descriptor> parameter used with steering rule\ntemplate.\n\n* Create tunnel matching flow rule:\ntunnel_match <tunnel descriptor> used with matching rule template.\n\n* If tunnel steering rule was offloaded, outer header of a partially\noffloaded packet is restored after miss.\n\nExample:\ntest packet=\n<Ether  dst=24:8a:07:8d:ae:d6 src=50:6b:4b:cc:fc:e2 type=IPv4 |\n<IP  version=4 ihl=5 proto=udp src=1.1.1.1 dst=1.1.1.10 |\n<UDP  sport=4789 dport=4789 len=58 chksum=0x7f7b |\n<VXLAN  NextProtocol=Ethernet vni=0x0 |\n<Ether  dst=24:aa:aa:aa:aa:d6 src=50:bb:bb:bb:bb:e2 type=IPv4 |\n<IP  version=4 ihl=5 proto=icmp src=2.2.2.2 dst=2.2.2.200 |\n<ICMP  type=echo-request code=0 chksum=0xf7ff id=0x0 seq=0x0 |>>>>>>>\n>>> len(packet)\n92\n\ntestpmd> flow flush 0\ntestpmd> port 0/queue 0: received 1 packets\nsrc=50:6B:4B:CC:FC:E2 - dst=24:8A:07:8D:AE:D6 - type=0x0800 -\nlength=92\n\ntestpmd> flow tunnel 0 type vxlan\nport 0: flow tunnel #1 type vxlan\ntestpmd> flow create 0 ingress group 0 tunnel_set 1\n         pattern eth /ipv4 / udp dst is 4789 / vxlan / end\n         actions  jump group 0 / end\nFlow rule #0 created\ntestpmd> port 0/queue 0: received 1 packets\ntunnel restore info: - vxlan tunnel - outer header present # <--\n  src=50:6B:4B:CC:FC:E2 - dst=24:8A:07:8D:AE:D6 - type=0x0800 -\nlength=92\n\ntestpmd> flow create 0 ingress group 0 tunnel_match 1\n         pattern eth / ipv4 / udp dst is 4789 / vxlan / eth / ipv4 /\n         end\n         actions set_mac_dst mac_addr 02:CA:FE:CA:FA:80 /\n         queue index 0 / end\nFlow rule #1 created\ntestpmd> port 0/queue 0: received 1 packets\n  src=50:BB:BB:BB:BB:E2 - dst=02:CA:FE:CA:FA:80 - type=0x0800 -\nlength=42\n\n* Destroy flow tunnel\nflow tunnel destroy <port> id <tunnel id>\n\n* Show existing flow tunnels\nflow tunnel list <port>\n\nSigned-off-by: Gregory Etelson <getelson@nvidia.com>\n---\nv2:\n* introduce testpmd support for tunnel offload API\n\nv3:\n* update flow tunnel commands\n\nv5:\n* rebase to next-net\n---\n app/test-pmd/cmdline_flow.c                 | 170 ++++++++++++-\n app/test-pmd/config.c                       | 252 +++++++++++++++++++-\n app/test-pmd/testpmd.c                      |   5 +-\n app/test-pmd/testpmd.h                      |  34 ++-\n app/test-pmd/util.c                         |  35 ++-\n doc/guides/testpmd_app_ug/testpmd_funcs.rst |  49 ++++\n 6 files changed, 532 insertions(+), 13 deletions(-)",
    "diff": "diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c\nindex 00c70a144a..b9a1f7178a 100644\n--- a/app/test-pmd/cmdline_flow.c\n+++ b/app/test-pmd/cmdline_flow.c\n@@ -74,6 +74,14 @@ enum index {\n \tLIST,\n \tAGED,\n \tISOLATE,\n+\tTUNNEL,\n+\n+\t/* Tunnel arguments. */\n+\tTUNNEL_CREATE,\n+\tTUNNEL_CREATE_TYPE,\n+\tTUNNEL_LIST,\n+\tTUNNEL_DESTROY,\n+\tTUNNEL_DESTROY_ID,\n \n \t/* Destroy arguments. */\n \tDESTROY_RULE,\n@@ -93,6 +101,8 @@ enum index {\n \tINGRESS,\n \tEGRESS,\n \tTRANSFER,\n+\tTUNNEL_SET,\n+\tTUNNEL_MATCH,\n \n \t/* Shared action arguments */\n \tSHARED_ACTION_CREATE,\n@@ -713,6 +723,7 @@ struct buffer {\n \t\t} sa; /* Shared action query arguments */\n \t\tstruct {\n \t\t\tstruct rte_flow_attr attr;\n+\t\t\tstruct tunnel_ops tunnel_ops;\n \t\t\tstruct rte_flow_item *pattern;\n \t\t\tstruct rte_flow_action *actions;\n \t\t\tuint32_t pattern_n;\n@@ -789,10 +800,32 @@ static const enum index next_vc_attr[] = {\n \tINGRESS,\n \tEGRESS,\n \tTRANSFER,\n+\tTUNNEL_SET,\n+\tTUNNEL_MATCH,\n \tPATTERN,\n \tZERO,\n };\n \n+static const enum index tunnel_create_attr[] = {\n+\tTUNNEL_CREATE,\n+\tTUNNEL_CREATE_TYPE,\n+\tEND,\n+\tZERO,\n+};\n+\n+static const enum index tunnel_destroy_attr[] = {\n+\tTUNNEL_DESTROY,\n+\tTUNNEL_DESTROY_ID,\n+\tEND,\n+\tZERO,\n+};\n+\n+static const enum index tunnel_list_attr[] = {\n+\tTUNNEL_LIST,\n+\tEND,\n+\tZERO,\n+};\n+\n static const enum index next_destroy_attr[] = {\n \tDESTROY_RULE,\n \tEND,\n@@ -1643,6 +1676,9 @@ static int parse_aged(struct context *, const struct token *,\n static int parse_isolate(struct context *, const struct token *,\n \t\t\t const char *, unsigned int,\n \t\t\t void *, unsigned int);\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_int(struct context *, const struct token *,\n \t\t     const char *, unsigned int,\n \t\t     void *, unsigned int);\n@@ -1844,7 +1880,8 @@ static const struct token token_list[] = {\n \t\t\t      LIST,\n \t\t\t      AGED,\n \t\t\t      QUERY,\n-\t\t\t      ISOLATE)),\n+\t\t\t      ISOLATE,\n+\t\t\t      TUNNEL)),\n \t\t.call = parse_init,\n \t},\n \t/* Top-level command. */\n@@ -1955,6 +1992,49 @@ 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[TUNNEL] = {\n+\t\t.name = \"tunnel\",\n+\t\t.help = \"new tunnel API\",\n+\t\t.next = NEXT(NEXT_ENTRY\n+\t\t\t     (TUNNEL_CREATE, TUNNEL_LIST, TUNNEL_DESTROY)),\n+\t\t.call = parse_tunnel,\n+\t},\n+\t/* Tunnel arguments. */\n+\t[TUNNEL_CREATE] = {\n+\t\t.name = \"create\",\n+\t\t.help = \"create new tunnel object\",\n+\t\t.next = NEXT(tunnel_create_attr, NEXT_ENTRY(PORT_ID)),\n+\t\t.args = ARGS(ARGS_ENTRY(struct buffer, port)),\n+\t\t.call = parse_tunnel,\n+\t},\n+\t[TUNNEL_CREATE_TYPE] = {\n+\t\t.name = \"type\",\n+\t\t.help = \"create new tunnel\",\n+\t\t.next = NEXT(tunnel_create_attr, NEXT_ENTRY(FILE_PATH)),\n+\t\t.args = ARGS(ARGS_ENTRY(struct tunnel_ops, type)),\n+\t\t.call = parse_tunnel,\n+\t},\n+\t[TUNNEL_DESTROY] = {\n+\t\t.name = \"destroy\",\n+\t\t.help = \"destroy tunel\",\n+\t\t.next = NEXT(tunnel_destroy_attr, NEXT_ENTRY(PORT_ID)),\n+\t\t.args = ARGS(ARGS_ENTRY(struct buffer, port)),\n+\t\t.call = parse_tunnel,\n+\t},\n+\t[TUNNEL_DESTROY_ID] = {\n+\t\t.name = \"id\",\n+\t\t.help = \"tunnel identifier to testroy\",\n+\t\t.next = NEXT(tunnel_destroy_attr, NEXT_ENTRY(UNSIGNED)),\n+\t\t.args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)),\n+\t\t.call = parse_tunnel,\n+\t},\n+\t[TUNNEL_LIST] = {\n+\t\t.name = \"list\",\n+\t\t.help = \"list existing tunnels\",\n+\t\t.next = NEXT(tunnel_list_attr, NEXT_ENTRY(PORT_ID)),\n+\t\t.args = ARGS(ARGS_ENTRY(struct buffer, port)),\n+\t\t.call = parse_tunnel,\n+\t},\n \t/* Destroy arguments. */\n \t[DESTROY_RULE] = {\n \t\t.name = \"rule\",\n@@ -2018,6 +2098,20 @@ static const struct token token_list[] = {\n \t\t.next = NEXT(next_vc_attr),\n \t\t.call = parse_vc,\n \t},\n+\t[TUNNEL_SET] = {\n+\t\t.name = \"tunnel_set\",\n+\t\t.help = \"tunnel steer rule\",\n+\t\t.next = NEXT(next_vc_attr, NEXT_ENTRY(UNSIGNED)),\n+\t\t.args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)),\n+\t\t.call = parse_vc,\n+\t},\n+\t[TUNNEL_MATCH] = {\n+\t\t.name = \"tunnel_match\",\n+\t\t.help = \"tunnel match rule\",\n+\t\t.next = NEXT(next_vc_attr, NEXT_ENTRY(UNSIGNED)),\n+\t\t.args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)),\n+\t\t.call = parse_vc,\n+\t},\n \t/* Validate/create pattern. */\n \t[PATTERN] = {\n \t\t.name = \"pattern\",\n@@ -4495,12 +4589,28 @@ parse_vc(struct context *ctx, const struct token *token,\n \t\treturn len;\n \t}\n \tctx->objdata = 0;\n-\tctx->object = &out->args.vc.attr;\n+\tswitch (ctx->curr) {\n+\tdefault:\n+\t\tctx->object = &out->args.vc.attr;\n+\t\tbreak;\n+\tcase TUNNEL_SET:\n+\tcase TUNNEL_MATCH:\n+\t\tctx->object = &out->args.vc.tunnel_ops;\n+\t\tbreak;\n+\t}\n \tctx->objmask = NULL;\n \tswitch (ctx->curr) {\n \tcase GROUP:\n \tcase PRIORITY:\n \t\treturn len;\n+\tcase TUNNEL_SET:\n+\t\tout->args.vc.tunnel_ops.enabled = 1;\n+\t\tout->args.vc.tunnel_ops.actions = 1;\n+\t\treturn len;\n+\tcase TUNNEL_MATCH:\n+\t\tout->args.vc.tunnel_ops.enabled = 1;\n+\t\tout->args.vc.tunnel_ops.items = 1;\n+\t\treturn len;\n \tcase INGRESS:\n \t\tout->args.vc.attr.ingress = 1;\n \t\treturn len;\n@@ -6108,6 +6218,47 @@ parse_isolate(struct context *ctx, const struct token *token,\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+\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) {\n+\t\tif (ctx->curr != TUNNEL)\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 TUNNEL_CREATE:\n+\t\tcase TUNNEL_DESTROY:\n+\t\tcase TUNNEL_LIST:\n+\t\t\tout->command = ctx->curr;\n+\t\t\tbreak;\n+\t\tcase TUNNEL_CREATE_TYPE:\n+\t\tcase TUNNEL_DESTROY_ID:\n+\t\t\tctx->object = &out->args.vc.tunnel_ops;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn len;\n+}\n+\n /**\n  * Parse signed/unsigned integers 8 to 64-bit long.\n  *\n@@ -7148,11 +7299,13 @@ cmd_flow_parsed(const struct buffer *in)\n \t\tbreak;\n \tcase VALIDATE:\n \t\tport_flow_validate(in->port, &in->args.vc.attr,\n-\t\t\t\t   in->args.vc.pattern, in->args.vc.actions);\n+\t\t\t\t   in->args.vc.pattern, in->args.vc.actions,\n+\t\t\t\t   &in->args.vc.tunnel_ops);\n \t\tbreak;\n \tcase CREATE:\n \t\tport_flow_create(in->port, &in->args.vc.attr,\n-\t\t\t\t in->args.vc.pattern, in->args.vc.actions);\n+\t\t\t\t in->args.vc.pattern, in->args.vc.actions,\n+\t\t\t\t &in->args.vc.tunnel_ops);\n \t\tbreak;\n \tcase DESTROY:\n \t\tport_flow_destroy(in->port, in->args.destroy.rule_n,\n@@ -7178,6 +7331,15 @@ cmd_flow_parsed(const struct buffer *in)\n \tcase AGED:\n \t\tport_flow_aged(in->port, in->args.aged.destroy);\n \t\tbreak;\n+\tcase TUNNEL_CREATE:\n+\t\tport_flow_tunnel_create(in->port, &in->args.vc.tunnel_ops);\n+\t\tbreak;\n+\tcase TUNNEL_DESTROY:\n+\t\tport_flow_tunnel_destroy(in->port, in->args.vc.tunnel_ops.id);\n+\t\tbreak;\n+\tcase TUNNEL_LIST:\n+\t\tport_flow_tunnel_list(in->port);\n+\t\tbreak;\n \tdefault:\n \t\tbreak;\n \t}\ndiff --git a/app/test-pmd/config.c b/app/test-pmd/config.c\nindex 2c00b55440..6bce791dfb 100644\n--- a/app/test-pmd/config.c\n+++ b/app/test-pmd/config.c\n@@ -1521,6 +1521,115 @@ port_mtu_set(portid_t port_id, uint16_t mtu)\n \n /* Generic flow management functions. */\n \n+static struct port_flow_tunnel *\n+port_flow_locate_tunnel_id(struct rte_port *port, uint32_t port_tunnel_id)\n+{\n+\tstruct port_flow_tunnel *flow_tunnel;\n+\n+\tLIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) {\n+\t\tif (flow_tunnel->id == port_tunnel_id)\n+\t\t\tgoto out;\n+\t}\n+\tflow_tunnel = NULL;\n+\n+out:\n+\treturn flow_tunnel;\n+}\n+\n+const char *\n+port_flow_tunnel_type(struct rte_flow_tunnel *tunnel)\n+{\n+\tconst char *type;\n+\tswitch (tunnel->type) {\n+\tdefault:\n+\t\ttype = \"unknown\";\n+\t\tbreak;\n+\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\ttype = \"vxlan\";\n+\t\tbreak;\n+\t}\n+\n+\treturn type;\n+}\n+\n+struct port_flow_tunnel *\n+port_flow_locate_tunnel(uint16_t port_id, struct rte_flow_tunnel *tun)\n+{\n+\tstruct rte_port *port = &ports[port_id];\n+\tstruct port_flow_tunnel *flow_tunnel;\n+\n+\tLIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) {\n+\t\tif (!memcmp(&flow_tunnel->tunnel, tun, sizeof(*tun)))\n+\t\t\tgoto out;\n+\t}\n+\tflow_tunnel = NULL;\n+\n+out:\n+\treturn flow_tunnel;\n+}\n+\n+void port_flow_tunnel_list(portid_t port_id)\n+{\n+\tstruct rte_port *port = &ports[port_id];\n+\tstruct port_flow_tunnel *flt;\n+\n+\tLIST_FOREACH(flt, &port->flow_tunnel_list, chain) {\n+\t\tprintf(\"port %u tunnel #%u type=%s\",\n+\t\t\tport_id, flt->id, port_flow_tunnel_type(&flt->tunnel));\n+\t\tif (flt->tunnel.tun_id)\n+\t\t\tprintf(\" id=%lu\", flt->tunnel.tun_id);\n+\t\tprintf(\"\\n\");\n+\t}\n+}\n+\n+void port_flow_tunnel_destroy(portid_t port_id, uint32_t tunnel_id)\n+{\n+\tstruct rte_port *port = &ports[port_id];\n+\tstruct port_flow_tunnel *flt;\n+\n+\tLIST_FOREACH(flt, &port->flow_tunnel_list, chain) {\n+\t\tif (flt->id == tunnel_id)\n+\t\t\tbreak;\n+\t}\n+\tif (flt) {\n+\t\tLIST_REMOVE(flt, chain);\n+\t\tfree(flt);\n+\t\tprintf(\"port %u: flow tunnel #%u destroyed\\n\",\n+\t\t\tport_id, tunnel_id);\n+\t}\n+}\n+\n+void port_flow_tunnel_create(portid_t port_id, const struct tunnel_ops *ops)\n+{\n+\tstruct rte_port *port = &ports[port_id];\n+\tenum rte_flow_item_type\ttype;\n+\tstruct port_flow_tunnel *flt;\n+\n+\tif (!strcmp(ops->type, \"vxlan\"))\n+\t\ttype = RTE_FLOW_ITEM_TYPE_VXLAN;\n+\telse {\n+\t\tprintf(\"cannot offload \\\"%s\\\" tunnel type\\n\", ops->type);\n+\t\treturn;\n+\t}\n+\tLIST_FOREACH(flt, &port->flow_tunnel_list, chain) {\n+\t\tif (flt->tunnel.type == type)\n+\t\t\tbreak;\n+\t}\n+\tif (!flt) {\n+\t\tflt = calloc(1, sizeof(*flt));\n+\t\tif (!flt) {\n+\t\t\tprintf(\"failed to allocate port flt object\\n\");\n+\t\t\treturn;\n+\t\t}\n+\t\tflt->tunnel.type = type;\n+\t\tflt->id = LIST_EMPTY(&port->flow_tunnel_list) ? 1 :\n+\t\t\t\t  LIST_FIRST(&port->flow_tunnel_list)->id + 1;\n+\t\tLIST_INSERT_HEAD(&port->flow_tunnel_list, flt, chain);\n+\t}\n+\tprintf(\"port %d: flow tunnel #%u type %s\\n\",\n+\t\tport_id, flt->id, ops->type);\n+}\n+\n /** Generate a port_flow entry from attributes/pattern/actions. */\n static struct port_flow *\n port_flow_new(const struct rte_flow_attr *attr,\n@@ -1860,20 +1969,137 @@ port_shared_action_query(portid_t port_id, uint32_t id)\n \t}\n \treturn ret;\n }\n+static struct port_flow_tunnel *\n+port_flow_tunnel_offload_cmd_prep(portid_t port_id,\n+\t\t\t\t  const struct rte_flow_item *pattern,\n+\t\t\t\t  const struct rte_flow_action *actions,\n+\t\t\t\t  const struct tunnel_ops *tunnel_ops)\n+{\n+\tint ret;\n+\tstruct rte_port *port;\n+\tstruct port_flow_tunnel *pft;\n+\tstruct rte_flow_error error;\n+\n+\tport = &ports[port_id];\n+\tpft = port_flow_locate_tunnel_id(port, tunnel_ops->id);\n+\tif (!pft) {\n+\t\tprintf(\"failed to locate port flow tunnel #%u\\n\",\n+\t\t\ttunnel_ops->id);\n+\t\treturn NULL;\n+\t}\n+\tif (tunnel_ops->actions) {\n+\t\tuint32_t num_actions;\n+\t\tconst struct rte_flow_action *aptr;\n+\n+\t\tret = rte_flow_tunnel_decap_set(port_id, &pft->tunnel,\n+\t\t\t\t\t\t&pft->pmd_actions,\n+\t\t\t\t\t\t&pft->num_pmd_actions,\n+\t\t\t\t\t\t&error);\n+\t\tif (ret) {\n+\t\t\tport_flow_complain(&error);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tfor (aptr = actions, num_actions = 1;\n+\t\t     aptr->type != RTE_FLOW_ACTION_TYPE_END;\n+\t\t     aptr++, num_actions++);\n+\t\tpft->actions = malloc(\n+\t\t\t\t(num_actions +  pft->num_pmd_actions) *\n+\t\t\t\tsizeof(actions[0]));\n+\t\tif (!pft->actions) {\n+\t\t\trte_flow_tunnel_action_decap_release(\n+\t\t\t\t\tport_id, pft->actions,\n+\t\t\t\t\tpft->num_pmd_actions, &error);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\trte_memcpy(pft->actions, pft->pmd_actions,\n+\t\t\t   pft->num_pmd_actions * sizeof(actions[0]));\n+\t\trte_memcpy(pft->actions + pft->num_pmd_actions, actions,\n+\t\t\t   num_actions * sizeof(actions[0]));\n+\t}\n+\tif (tunnel_ops->items) {\n+\t\tuint32_t num_items;\n+\t\tconst struct rte_flow_item *iptr;\n+\n+\t\tret = rte_flow_tunnel_match(port_id, &pft->tunnel,\n+\t\t\t\t\t    &pft->pmd_items,\n+\t\t\t\t\t    &pft->num_pmd_items,\n+\t\t\t\t\t    &error);\n+\t\tif (ret) {\n+\t\t\tport_flow_complain(&error);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tfor (iptr = pattern, num_items = 1;\n+\t\t     iptr->type != RTE_FLOW_ITEM_TYPE_END;\n+\t\t     iptr++, num_items++);\n+\t\tpft->items = malloc((num_items + pft->num_pmd_items) *\n+\t\t\t\t    sizeof(pattern[0]));\n+\t\tif (!pft->items) {\n+\t\t\trte_flow_tunnel_item_release(\n+\t\t\t\t\tport_id, pft->pmd_items,\n+\t\t\t\t\tpft->num_pmd_items, &error);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\trte_memcpy(pft->items, pft->pmd_items,\n+\t\t\t   pft->num_pmd_items * sizeof(pattern[0]));\n+\t\trte_memcpy(pft->items + pft->num_pmd_items, pattern,\n+\t\t\t   num_items * sizeof(pattern[0]));\n+\t}\n+\n+\treturn pft;\n+}\n+\n+static void\n+port_flow_tunnel_offload_cmd_release(portid_t port_id,\n+\t\t\t\t     const struct tunnel_ops *tunnel_ops,\n+\t\t\t\t     struct port_flow_tunnel *pft)\n+{\n+\tstruct rte_flow_error error;\n+\n+\tif (tunnel_ops->actions) {\n+\t\tfree(pft->actions);\n+\t\trte_flow_tunnel_action_decap_release(\n+\t\t\tport_id, pft->pmd_actions,\n+\t\t\tpft->num_pmd_actions, &error);\n+\t\tpft->actions = NULL;\n+\t\tpft->pmd_actions = NULL;\n+\t}\n+\tif (tunnel_ops->items) {\n+\t\tfree(pft->items);\n+\t\trte_flow_tunnel_item_release(port_id, pft->pmd_items,\n+\t\t\t\t\t     pft->num_pmd_items,\n+\t\t\t\t\t     &error);\n+\t\tpft->items = NULL;\n+\t\tpft->pmd_items = NULL;\n+\t}\n+}\n \n /** Validate flow rule. */\n int\n port_flow_validate(portid_t port_id,\n \t\t   const struct rte_flow_attr *attr,\n \t\t   const struct rte_flow_item *pattern,\n-\t\t   const struct rte_flow_action *actions)\n+\t\t   const struct rte_flow_action *actions,\n+\t\t   const struct tunnel_ops *tunnel_ops)\n {\n \tstruct rte_flow_error error;\n+\tstruct port_flow_tunnel *pft = NULL;\n \n \t/* Poisoning to make sure PMDs update it in case of error. */\n \tmemset(&error, 0x11, sizeof(error));\n+\tif (tunnel_ops->enabled) {\n+\t\tpft = port_flow_tunnel_offload_cmd_prep(port_id, pattern,\n+\t\t\t\t\t\t\tactions, tunnel_ops);\n+\t\tif (!pft)\n+\t\t\treturn -ENOENT;\n+\t\tif (pft->items)\n+\t\t\tpattern = pft->items;\n+\t\tif (pft->actions)\n+\t\t\tactions = pft->actions;\n+\t}\n \tif (rte_flow_validate(port_id, attr, pattern, actions, &error))\n \t\treturn port_flow_complain(&error);\n+\tif (tunnel_ops->enabled)\n+\t\tport_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft);\n \tprintf(\"Flow rule validated\\n\");\n \treturn 0;\n }\n@@ -1903,13 +2129,15 @@ int\n port_flow_create(portid_t port_id,\n \t\t const struct rte_flow_attr *attr,\n \t\t const struct rte_flow_item *pattern,\n-\t\t const struct rte_flow_action *actions)\n+\t\t const struct rte_flow_action *actions,\n+\t\t const struct tunnel_ops *tunnel_ops)\n {\n \tstruct rte_flow *flow;\n \tstruct rte_port *port;\n \tstruct port_flow *pf;\n \tuint32_t id = 0;\n \tstruct rte_flow_error error;\n+\tstruct port_flow_tunnel *pft = NULL;\n \n \tport = &ports[port_id];\n \tif (port->flow_list) {\n@@ -1920,6 +2148,16 @@ port_flow_create(portid_t port_id,\n \t\t}\n \t\tid = port->flow_list->id + 1;\n \t}\n+\tif (tunnel_ops->enabled) {\n+\t\tpft = port_flow_tunnel_offload_cmd_prep(port_id, pattern,\n+\t\t\t\t\t\t\tactions, tunnel_ops);\n+\t\tif (!pft)\n+\t\t\treturn -ENOENT;\n+\t\tif (pft->items)\n+\t\t\tpattern = pft->items;\n+\t\tif (pft->actions)\n+\t\t\tactions = pft->actions;\n+\t}\n \tpf = port_flow_new(attr, pattern, actions, &error);\n \tif (!pf)\n \t\treturn port_flow_complain(&error);\n@@ -1935,6 +2173,8 @@ port_flow_create(portid_t port_id,\n \tpf->id = id;\n \tpf->flow = flow;\n \tport->flow_list = pf;\n+\tif (tunnel_ops->enabled)\n+\t\tport_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft);\n \tprintf(\"Flow rule #%u created\\n\", pf->id);\n \treturn 0;\n }\n@@ -2244,7 +2484,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group)\n \t\t       pf->rule.attr->egress ? 'e' : '-',\n \t\t       pf->rule.attr->transfer ? 't' : '-');\n \t\twhile (item->type != RTE_FLOW_ITEM_TYPE_END) {\n-\t\t\tif (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR,\n+\t\t\tif ((uint32_t)item->type > INT_MAX)\n+\t\t\t\tname = \"PMD_INTERNAL\";\n+\t\t\telse if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR,\n \t\t\t\t\t  &name, sizeof(name),\n \t\t\t\t\t  (void *)(uintptr_t)item->type,\n \t\t\t\t\t  NULL) <= 0)\n@@ -2255,7 +2497,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group)\n \t\t}\n \t\tprintf(\"=>\");\n \t\twhile (action->type != RTE_FLOW_ACTION_TYPE_END) {\n-\t\t\tif (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,\n+\t\t\tif ((uint32_t)action->type > INT_MAX)\n+\t\t\t\tname = \"PMD_INTERNAL\";\n+\t\t\telse if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,\n \t\t\t\t\t  &name, sizeof(name),\n \t\t\t\t\t  (void *)(uintptr_t)action->type,\n \t\t\t\t\t  NULL) <= 0)\ndiff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c\nindex 6caba60988..333904d686 100644\n--- a/app/test-pmd/testpmd.c\n+++ b/app/test-pmd/testpmd.c\n@@ -3684,6 +3684,8 @@ init_port_dcb_config(portid_t pid,\n static void\n init_port(void)\n {\n+\tint i;\n+\n \t/* Configuration of Ethernet ports. */\n \tports = rte_zmalloc(\"testpmd: ports\",\n \t\t\t    sizeof(struct rte_port) * RTE_MAX_ETHPORTS,\n@@ -3693,7 +3695,8 @@ init_port(void)\n \t\t\t\t\"rte_zmalloc(%d struct rte_port) failed\\n\",\n \t\t\t\tRTE_MAX_ETHPORTS);\n \t}\n-\n+\tfor (i = 0; i < RTE_MAX_ETHPORTS; i++)\n+\t\tLIST_INIT(&ports[i].flow_tunnel_list);\n \t/* Initialize ports NUMA structures */\n \tmemset(port_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);\n \tmemset(rxring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);\ndiff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h\nindex f8b0a3517d..5238ac3dd5 100644\n--- a/app/test-pmd/testpmd.h\n+++ b/app/test-pmd/testpmd.h\n@@ -12,6 +12,7 @@\n #include <rte_gro.h>\n #include <rte_gso.h>\n #include <cmdline.h>\n+#include <sys/queue.h>\n \n #define RTE_PORT_ALL            (~(portid_t)0x0)\n \n@@ -150,6 +151,26 @@ struct port_shared_action {\n \tstruct rte_flow_shared_action *action;\t/**< Shared action handle. */\n };\n \n+struct port_flow_tunnel {\n+\tLIST_ENTRY(port_flow_tunnel) chain;\n+\tstruct rte_flow_action *pmd_actions;\n+\tstruct rte_flow_item   *pmd_items;\n+\tuint32_t id;\n+\tuint32_t num_pmd_actions;\n+\tuint32_t num_pmd_items;\n+\tstruct rte_flow_tunnel tunnel;\n+\tstruct rte_flow_action *actions;\n+\tstruct rte_flow_item *items;\n+};\n+\n+struct tunnel_ops {\n+\tuint32_t id;\n+\tchar type[16];\n+\tuint32_t enabled:1;\n+\tuint32_t actions:1;\n+\tuint32_t items:1;\n+};\n+\n /**\n  * The data structure associated with each port.\n  */\n@@ -182,6 +203,7 @@ struct rte_port {\n \tstruct port_flow        *flow_list; /**< Associated flows. */\n \tstruct port_shared_action *actions_list;\n \t/**< Associated shared actions. */\n+\tLIST_HEAD(, port_flow_tunnel) flow_tunnel_list;\n \tconst struct rte_eth_rxtx_callback *rx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1];\n \tconst struct rte_eth_rxtx_callback *tx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1];\n \t/**< metadata value to insert in Tx packets. */\n@@ -773,11 +795,13 @@ int port_shared_action_update(portid_t port_id, uint32_t id,\n int port_flow_validate(portid_t port_id,\n \t\t       const struct rte_flow_attr *attr,\n \t\t       const struct rte_flow_item *pattern,\n-\t\t       const struct rte_flow_action *actions);\n+\t\t       const struct rte_flow_action *actions,\n+\t\t       const struct tunnel_ops *tunnel_ops);\n int port_flow_create(portid_t port_id,\n \t\t     const struct rte_flow_attr *attr,\n \t\t     const struct rte_flow_item *pattern,\n-\t\t     const struct rte_flow_action *actions);\n+\t\t     const struct rte_flow_action *actions,\n+\t\t     const struct tunnel_ops *tunnel_ops);\n int port_shared_action_query(portid_t port_id, uint32_t id);\n void update_age_action_context(const struct rte_flow_action *actions,\n \t\t     struct port_flow *pf);\n@@ -788,6 +812,12 @@ int port_flow_query(portid_t port_id, uint32_t rule,\n \t\t    const struct rte_flow_action *action);\n void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group);\n void port_flow_aged(portid_t port_id, uint8_t destroy);\n+const char *port_flow_tunnel_type(struct rte_flow_tunnel *tunnel);\n+struct port_flow_tunnel *\n+port_flow_locate_tunnel(uint16_t port_id, struct rte_flow_tunnel *tun);\n+void port_flow_tunnel_list(portid_t port_id);\n+void port_flow_tunnel_destroy(portid_t port_id, uint32_t tunnel_id);\n+void port_flow_tunnel_create(portid_t port_id, const struct tunnel_ops *ops);\n int port_flow_isolate(portid_t port_id, int set);\n \n void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id);\ndiff --git a/app/test-pmd/util.c b/app/test-pmd/util.c\nindex 8488fa1a8f..781a813759 100644\n--- a/app/test-pmd/util.c\n+++ b/app/test-pmd/util.c\n@@ -48,18 +48,49 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],\n \t       is_rx ? \"received\" : \"sent\",\n \t       (unsigned int) nb_pkts);\n \tfor (i = 0; i < nb_pkts; i++) {\n+\t\tint ret;\n+\t\tstruct rte_flow_error error;\n+\t\tstruct rte_flow_restore_info info = { 0, };\n+\n \t\tmb = pkts[i];\n \t\teth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);\n \t\teth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);\n-\t\tol_flags = mb->ol_flags;\n \t\tpacket_type = mb->packet_type;\n \t\tis_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);\n-\n+\t\tret = rte_flow_get_restore_info(port_id, mb, &info, &error);\n+\t\tif (!ret) {\n+\t\t\tprintf(\"restore info:\");\n+\t\t\tif (info.flags & RTE_FLOW_RESTORE_INFO_TUNNEL) {\n+\t\t\t\tstruct port_flow_tunnel *port_tunnel;\n+\n+\t\t\t\tport_tunnel = port_flow_locate_tunnel\n+\t\t\t\t\t      (port_id, &info.tunnel);\n+\t\t\t\tprintf(\" - tunnel\");\n+\t\t\t\tif (port_tunnel)\n+\t\t\t\t\tprintf(\" #%u\", port_tunnel->id);\n+\t\t\t\telse\n+\t\t\t\t\tprintf(\" %s\", \"-none-\");\n+\t\t\t\tprintf(\" type %s\",\n+\t\t\t\t\tport_flow_tunnel_type(&info.tunnel));\n+\t\t\t} else {\n+\t\t\t\tprintf(\" - no tunnel info\");\n+\t\t\t}\n+\t\t\tif (info.flags & RTE_FLOW_RESTORE_INFO_ENCAPSULATED)\n+\t\t\t\tprintf(\" - outer header present\");\n+\t\t\telse\n+\t\t\t\tprintf(\" - no outer header\");\n+\t\t\tif (info.flags & RTE_FLOW_RESTORE_INFO_GROUP_ID)\n+\t\t\t\tprintf(\" - miss group %u\", info.group_id);\n+\t\t\telse\n+\t\t\t\tprintf(\" - no miss group\");\n+\t\t\tprintf(\"\\n\");\n+\t\t}\n \t\tprint_ether_addr(\"  src=\", &eth_hdr->s_addr);\n \t\tprint_ether_addr(\" - dst=\", &eth_hdr->d_addr);\n \t\tprintf(\" - type=0x%04x - length=%u - nb_segs=%d\",\n \t\t       eth_type, (unsigned int) mb->pkt_len,\n \t\t       (int)mb->nb_segs);\n+\t\tol_flags = mb->ol_flags;\n \t\tif (ol_flags & PKT_RX_RSS_HASH) {\n \t\t\tprintf(\" - RSS hash=0x%x\", (unsigned int) mb->hash.rss);\n \t\t\tprintf(\" - RSS queue=0x%x\", (unsigned int) queue);\ndiff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\nindex 43c0ea0599..05a4446757 100644\n--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n@@ -3749,6 +3749,45 @@ following sections.\n \n    flow aged {port_id} [destroy]\n \n+- Tunnel offload - create a tunnel stub::\n+\n+   flow tunnel create {port_id} type {tunnel_type}\n+\n+- Tunnel offload - destroy a tunnel stub::\n+\n+   flow tunnel destroy {port_id} id {tunnel_id}\n+\n+- Tunnel offload - list port tunnel stubs::\n+\n+   flow tunnel list {port_id}\n+\n+Creating a tunnel stub for offload\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+``flow tunnel create`` setup a tunnel stub for tunnel offload flow rules::\n+\n+   flow tunnel create {port_id} type {tunnel_type}\n+\n+If successful, it will return a tunnel stub ID usable with other commands::\n+\n+   port [...]: flow tunnel #[...] type [...]\n+\n+Tunnel stub ID is relative to a port.\n+\n+Destroying tunnel offload stub\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+``flow tunnel destroy`` destroy port tunnel stub::\n+\n+   flow tunnel destroy {port_id} id {tunnel_id}\n+\n+Listing tunnel offload stubs\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+``flow tunnel list`` list port tunnel offload stubs::\n+\n+   flow tunnel list {port_id}\n+\n Validating flow rules\n ~~~~~~~~~~~~~~~~~~~~~\n \n@@ -3795,6 +3834,7 @@ to ``rte_flow_create()``::\n \n    flow create {port_id}\n       [group {group_id}] [priority {level}] [ingress] [egress] [transfer]\n+      [tunnel_set {tunnel_id}] [tunnel_match {tunnel_id}]\n       pattern {item} [/ {item} [...]] / end\n       actions {action} [/ {action} [...]] / end\n \n@@ -3809,6 +3849,7 @@ Otherwise it will show an error message of the form::\n Parameters describe in the following order:\n \n - Attributes (*group*, *priority*, *ingress*, *egress*, *transfer* tokens).\n+- Tunnel offload specification (tunnel_set, tunnel_match)\n - A matching pattern, starting with the *pattern* token and terminated by an\n   *end* pattern item.\n - Actions, starting with the *actions* token and terminated by an *end*\n@@ -3852,6 +3893,14 @@ Most rules affect RX therefore contain the ``ingress`` token::\n \n    testpmd> flow create 0 ingress pattern [...]\n \n+Tunnel offload\n+^^^^^^^^^^^^^^\n+\n+Indicate tunnel offload rule type\n+\n+- ``tunnel_set {tunnel_id}``: mark rule as tunnel offload decap_set type.\n+- ``tunnel_match {tunnel_id}``:  mark rule as tunel offload match type.\n+\n Matching pattern\n ^^^^^^^^^^^^^^^^\n \n",
    "prefixes": [
        "v6",
        "3/3"
    ]
}