get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 76932,
    "url": "http://patches.dpdk.org/api/patches/76932/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200908201552.14423-5-getelson@nvidia.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20200908201552.14423-5-getelson@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200908201552.14423-5-getelson@nvidia.com",
    "date": "2020-09-08T20:15:51",
    "name": "[v2,4/4] app/testpmd: support tunnel offload API",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "31cf490e14bf102aebb8c07ae0afc7a930b06ff2",
    "submitter": {
        "id": 1882,
        "url": "http://patches.dpdk.org/api/people/1882/?format=api",
        "name": "Gregory Etelson",
        "email": "getelson@nvidia.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20200908201552.14423-5-getelson@nvidia.com/mbox/",
    "series": [
        {
            "id": 12033,
            "url": "http://patches.dpdk.org/api/series/12033/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=12033",
            "date": "2020-09-08T20:15:47",
            "name": "Tunnel Offload API",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/12033/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/76932/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/76932/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 71F9EA04B1;\n\tTue,  8 Sep 2020 22:17:02 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id B16921C0CA;\n\tTue,  8 Sep 2020 22:16:48 +0200 (CEST)",
            "from hqnvemgate26.nvidia.com (hqnvemgate26.nvidia.com\n [216.228.121.65]) by dpdk.org (Postfix) with ESMTP id 2BBB71C0CA\n for <dev@dpdk.org>; Tue,  8 Sep 2020 22:16:47 +0200 (CEST)",
            "from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by\n hqnvemgate26.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA)\n id <B5f57e6a10001>; Tue, 08 Sep 2020 13:16:33 -0700",
            "from hqmail.nvidia.com ([172.20.161.6])\n by hqpgpgate101.nvidia.com (PGP Universal service);\n Tue, 08 Sep 2020 13:16:46 -0700",
            "from nvidia.com (10.124.1.5) by HQMAIL107.nvidia.com (172.20.187.13)\n with Microsoft SMTP Server (TLS) id 15.0.1473.3;\n Tue, 8 Sep 2020 20:16:28 +0000"
        ],
        "X-PGP-Universal": "processed;\n by hqpgpgate101.nvidia.com on Tue, 08 Sep 2020 13:16:46 -0700",
        "From": "Gregory Etelson <getelson@nvidia.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<matan@nvidia.com>, <rasland@nvidia.com>, <orika@nvidia.com>, Ori Kam\n <orika@mellanox.com>, Wenzhuo Lu <wenzhuo.lu@intel.com>, Beilei Xing\n <beilei.xing@intel.com>, Bernard Iremonger <bernard.iremonger@intel.com>",
        "Date": "Tue, 8 Sep 2020 23:15:51 +0300",
        "Message-ID": "<20200908201552.14423-5-getelson@nvidia.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20200908201552.14423-1-getelson@nvidia.com>",
        "References": "<20200625160348.26220-1-getelson@mellanox.com>\n <20200908201552.14423-1-getelson@nvidia.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "quoted-printable",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.124.1.5]",
        "X-ClientProxiedBy": "HQMAIL101.nvidia.com (172.20.187.10) To\n HQMAIL107.nvidia.com (172.20.187.13)",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1;\n t=1599596193; bh=UmqsGd3nkRGKbKGN34zJmTDUWPiUuU/CASLTbQB43pw=;\n h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer:\n In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:\n Content-Type:X-Originating-IP:X-ClientProxiedBy;\n b=j7tBLWTlMiqb7oYA2EjTLdv+49ufyGqWzocikQprha9cBY8Q26QbJUOfaJPhAgjm1\n qHJqL88tW/VYBRHsUwqAD7GuqMOO0b3AFQr4chYFS2bBDCjWDEqaNdmTWhU5d2PLS8\n dMDqgqvw2Y/cBUWVkgUNjem81BYhnFAmzqJx0lh67x6bA1GeJ4H/vmN54jpN+YHi/m\n cLLgsypi5xXwz1Nj+8t+syeuEDGsUKQ121QF60PIcBwA2MhldXwqkPyL3/RuHVEEEw\n ZxlZ95pIp1un7alV9q/x2uT/u8OlNOghgTSq3L9LJs4BeGNSN12fsEGymONnKdTqpH\n 3pfAvv0qdS18A==",
        "Subject": "[dpdk-dev] [PATCH v2 4/4] app/testpmd: support tunnel offload API",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "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 <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\nTODO: add tunnel destruction command.\n\nSigned-off-by: Gregory Etelson <getelson@nvidia.com>\n---\nv2:\n* introduce testpmd support for tunnel offload API\n---\n app/test-pmd/cmdline_flow.c | 102 ++++++++++++++++++++++++-\n app/test-pmd/config.c       | 147 +++++++++++++++++++++++++++++++++++-\n app/test-pmd/testpmd.c      |   5 +-\n app/test-pmd/testpmd.h      |  27 ++++++-\n app/test-pmd/util.c         |  30 +++++++-\n 5 files changed, 302 insertions(+), 9 deletions(-)",
    "diff": "diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c\nindex 6263d307ed..f0a7a4a9ea 100644\n--- a/app/test-pmd/cmdline_flow.c\n+++ b/app/test-pmd/cmdline_flow.c\n@@ -69,6 +69,10 @@ enum index {\n \tLIST,\n \tAGED,\n \tISOLATE,\n+\tTUNNEL,\n+\n+\t/* Tunnel argumens. */\n+\tTUNNEL_RULE,\n \n \t/* Destroy arguments. */\n \tDESTROY_RULE,\n@@ -88,6 +92,8 @@ enum index {\n \tINGRESS,\n \tEGRESS,\n \tTRANSFER,\n+\tTUNNEL_SET,\n+\tTUNNEL_MATCH,\n \n \t/* Validate/create pattern. */\n \tPATTERN,\n@@ -653,6 +659,7 @@ struct buffer {\n \tunion {\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@@ -713,10 +720,18 @@ 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 next_tunnel_attr[] = {\n+\tTUNNEL_RULE,\n+\tEND,\n+\tZERO,\n+};\n+\n static const enum index next_destroy_attr[] = {\n \tDESTROY_RULE,\n \tEND,\n@@ -1516,6 +1531,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@@ -1698,7 +1716,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/* Sub-level commands. */\n@@ -1772,6 +1791,21 @@ 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(TUNNEL_RULE), 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 arguments. */\n+\t[TUNNEL_RULE]{\n+\t\t.name = \"type\",\n+\t\t.help = \"specify tunnel type\",\n+\t\t.next = NEXT(next_tunnel_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/* Destroy arguments. */\n \t[DESTROY_RULE] = {\n \t\t.name = \"rule\",\n@@ -1835,6 +1869,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@@ -4054,12 +4102,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@@ -5597,6 +5661,34 @@ 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}\n+\tif (ctx->curr == TUNNEL_RULE)\n+\t\tctx->object = &out->args.vc.tunnel_ops;\n+\treturn len;\n+}\n+\n /**\n  * Parse signed/unsigned integers 8 to 64-bit long.\n  *\n@@ -6547,7 +6639,8 @@ cmd_flow_parsed(const struct buffer *in)\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@@ -6573,6 +6666,9 @@ 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:\n+\t\tport_flow_add_tunnel(in->port, &in->args.vc.tunnel_ops);\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 30bee33248..b90927f451 100644\n--- a/app/test-pmd/config.c\n+++ b/app/test-pmd/config.c\n@@ -1337,6 +1337,58 @@ 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(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+void port_flow_release_tunnel(struct port_flow_tunnel *flow_tunnel)\n+{\n+\tLIST_REMOVE(flow_tunnel, chain);\n+\tfree(flow_tunnel);\n+}\n+\n+void port_flow_add_tunnel(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 *flow_tunnel;\n+\n+\tif (!strncmp(ops->type, \"vxlan\", strlen(\"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(flow_tunnel, &port->flow_tunnel_list, chain) {\n+\t\tif (flow_tunnel->tunnel.type == type)\n+\t\t\tbreak;\n+\t}\n+\tif (!flow_tunnel) {\n+\t\tflow_tunnel = calloc(1, sizeof(*flow_tunnel));\n+\t\tif (!flow_tunnel) {\n+\t\t\tprintf(\"failed to allocate port flow_tunnel object\\n\");\n+\t\t\treturn;\n+\t\t}\n+\t\tflow_tunnel->tunnel.type = type;\n+\t\tflow_tunnel->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, flow_tunnel, chain);\n+\t}\n+\tprintf(\"port %d: flow tunnel #%u type %s\\n\",\n+\t\tport_id, flow_tunnel->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@@ -1503,13 +1555,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;\n \n \tport = &ports[port_id];\n \tif (port->flow_list) {\n@@ -1520,6 +1574,75 @@ 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\tint ret;\n+\t\tpft = port_flow_locate_tunnel(port, tunnel_ops->id);\n+\t\tif (!pft) {\n+\t\t\tprintf(\"failed to locate port flow tunnel #%u\\n\",\n+\t\t\t\ttunnel_ops->id);\n+\t\t\treturn -ENOENT;\n+\t\t}\n+\t\tif (tunnel_ops->actions) {\n+\t\t\tuint32_t num_actions;\n+\t\t\tconst struct rte_flow_action *aptr;\n+\n+\t\t\tret = rte_flow_tunnel_decap_set(port_id, &pft->tunnel,\n+\t\t\t\t\t\t\t&pft->pmd_actions,\n+\t\t\t\t\t\t\t&pft->num_pmd_actions,\n+\t\t\t\t\t\t\t&error);\n+\t\t\tif (ret) {\n+\t\t\t\tport_flow_complain(&error);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\tfor (aptr = actions, num_actions = 1;\n+\t\t\t     aptr->type != RTE_FLOW_ACTION_TYPE_END;\n+\t\t\t     aptr++, num_actions++);\n+\t\t\tpft->actions = malloc(\n+\t\t\t\t\t(num_actions +  pft->num_pmd_actions) *\n+\t\t\t\t\tsizeof(actions[0]));\n+\t\t\tif (!pft->actions) {\n+\t\t\t\trte_flow_tunnel_action_decap_release(\n+\t\t\t\t\t\tport_id, pft->actions,\n+\t\t\t\t\t\tpft->num_pmd_actions, &error);\n+\t\t\t\treturn -ENOMEM;\n+\t\t\t}\n+\t\t\trte_memcpy(pft->actions, pft->pmd_actions,\n+\t\t\t\t   pft->num_pmd_actions * sizeof(actions[0]));\n+\t\t\trte_memcpy(pft->actions + pft->num_pmd_actions, actions,\n+\t\t\t\t   num_actions * sizeof(actions[0]));\n+\t\t\tactions = pft->actions;\n+\t\t}\n+\t\tif (tunnel_ops->items) {\n+\t\t\tuint32_t num_items;\n+\t\t\tconst struct rte_flow_item *iptr;\n+\n+\t\t\tret = rte_flow_tunnel_match(port_id, &pft->tunnel,\n+\t\t\t\t\t\t    &pft->pmd_items,\n+\t\t\t\t\t\t    &pft->num_pmd_items,\n+\t\t\t\t\t\t    &error);\n+\t\t\tif (ret) {\n+\t\t\t\tport_flow_complain(&error);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\tfor (iptr = pattern, num_items = 1;\n+\t\t\t     iptr->type != RTE_FLOW_ITEM_TYPE_END;\n+\t\t\t     iptr++, num_items++);\n+\t\t\tpft->items = malloc((num_items + pft->num_pmd_items) *\n+\t\t\t\t\t    sizeof(pattern[0]));\n+\t\t\tif (!pft->items) {\n+\t\t\t\trte_flow_tunnel_item_release(\n+\t\t\t\t\t\tport_id, pft->pmd_items,\n+\t\t\t\t\t\tpft->num_pmd_items, &error);\n+\t\t\t\treturn -ENOMEM;\n+\t\t\t}\n+\t\t\trte_memcpy(pft->items, pft->pmd_items,\n+\t\t\t\t   pft->num_pmd_items * sizeof(pattern[0]));\n+\t\t\trte_memcpy(pft->items + pft->num_pmd_items, pattern,\n+\t\t\t\t   num_items * sizeof(pattern[0]));\n+\t\t\tpattern = pft->items;\n+\t\t}\n+\n+\t}\n \tpf = port_flow_new(attr, pattern, actions, &error);\n \tif (!pf)\n \t\treturn port_flow_complain(&error);\n@@ -1535,6 +1658,20 @@ 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\tif (tunnel_ops->actions) {\n+\t\t\tfree(pft->actions);\n+\t\t\trte_flow_tunnel_action_decap_release(\n+\t\t\t\tport_id, pft->pmd_actions,\n+\t\t\t\tpft->num_pmd_actions, &error);\n+\t\t}\n+\t\tif (tunnel_ops->items) {\n+\t\t\tfree(pft->items);\n+\t\t\trte_flow_tunnel_item_release(port_id, pft->pmd_items,\n+\t\t\t\t\t\t     pft->num_pmd_items,\n+\t\t\t\t\t\t     &error);\n+\t\t}\n+\t}\n \tprintf(\"Flow rule #%u created\\n\", pf->id);\n \treturn 0;\n }\n@@ -1829,7 +1966,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])\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@@ -1840,7 +1979,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])\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 7842c3b781..e2330116e1 100644\n--- a/app/test-pmd/testpmd.c\n+++ b/app/test-pmd/testpmd.c\n@@ -3591,6 +3591,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@@ -3600,7 +3602,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 25a12b14f2..9c47533c68 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@@ -148,6 +149,26 @@ struct port_flow {\n \tuint8_t data[]; /**< Storage for flow rule description */\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@@ -178,6 +199,7 @@ struct rte_port {\n \tuint32_t                mc_addr_nb; /**< nb. of addr. in mc_addr_pool */\n \tuint8_t                 slave_flag; /**< bonding slave port */\n \tstruct port_flow        *flow_list; /**< Associated flows. */\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@@ -729,7 +751,8 @@ int port_flow_validate(portid_t port_id,\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 void update_age_action_context(const struct rte_flow_action *actions,\n \t\t     struct port_flow *pf);\n int port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule);\n@@ -739,6 +762,8 @@ 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+void port_flow_release_tunnel(struct port_flow_tunnel *flow_tunnel);\n+void port_flow_add_tunnel(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..6757acde9a 100644\n--- a/app/test-pmd/util.c\n+++ b/app/test-pmd/util.c\n@@ -22,6 +22,12 @@ print_ether_addr(const char *what, const struct rte_ether_addr *eth_addr)\n \tprintf(\"%s%s\", what, buf);\n }\n \n+static bool tunnel_missed_packet(struct rte_mbuf  *mb)\n+{\n+\tuint64_t mask = PKT_RX_FDIR | PKT_RX_FDIR_ID;\n+\treturn (mb->ol_flags & mask) == mask;\n+}\n+\n static inline void\n dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],\n \t      uint16_t nb_pkts, int is_rx)\n@@ -51,15 +57,37 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],\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\tif (tunnel_missed_packet(mb)) {\n+\t\t\tint ret;\n+\t\t\tstruct rte_flow_error error;\n+\t\t\tstruct rte_flow_restore_info info = { 0, };\n+\n+\t\t\tret = rte_flow_tunnel_get_restore_info(port_id, mb,\n+\t\t\t\t\t\t\t       &info, &error);\n+\t\t\tif (!ret) {\n+\t\t\t\tprintf(\"tunnel restore info:\");\n+\t\t\t\tif (info.flags & RTE_FLOW_RESTORE_INFO_TUNNEL)\n+\t\t\t\t\tif (info.tunnel.type ==\n+\t\t\t\t\t    RTE_FLOW_ITEM_TYPE_VXLAN)\n+\t\t\t\t\t\tprintf(\" - vxlan tunnel\");\n+\t\t\t\tif (info.flags &\n+\t\t\t\t    RTE_FLOW_RESTORE_INFO_ENCAPSULATED)\n+\t\t\t\t\tprintf(\" - outer header present\");\n+\t\t\t\tif (info.flags & RTE_FLOW_RESTORE_INFO_GROUP_ID)\n+\t\t\t\t\tprintf(\" - miss group %u\",\n+\t\t\t\t\t\tinfo.group_id);\n+\t\t\t}\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);\n",
    "prefixes": [
        "v2",
        "4/4"
    ]
}