Show a patch.

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

{
    "id": 44070,
    "url": "http://patches.dpdk.org/api/patches/44070/",
    "web_url": "http://patches.dpdk.org/patch/44070/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/",
        "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"
    },
    "msgid": "<20180831085337.21419-4-adrien.mazarguil@6wind.com>",
    "date": "2018-08-31T09:01:05",
    "name": "[v3,3/7] app/testpmd: rely on flow API conversion function",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "9b51d3e673319a7ff7521b523e1c5ee2867797e8",
    "submitter": {
        "id": 165,
        "url": "http://patches.dpdk.org/api/people/165/",
        "name": "Adrien Mazarguil",
        "email": "adrien.mazarguil@6wind.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@intel.com"
    },
    "mbox": "http://patches.dpdk.org/patch/44070/mbox/",
    "series": [
        {
            "id": 1123,
            "url": "http://patches.dpdk.org/api/series/1123/",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1123",
            "date": "2018-08-31T09:00:57",
            "name": "ethdev: add flow API object converter",
            "version": 3,
            "mbox": "http://patches.dpdk.org/series/1123/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/44070/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/44070/checks/",
    "tags": {},
    "headers": {
        "X-Mailman-Version": "2.1.15",
        "In-Reply-To": "<20180831085337.21419-1-adrien.mazarguil@6wind.com>",
        "Errors-To": "dev-bounces@dpdk.org",
        "X-Mailer": "git-send-email 2.11.0",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 5D3ED4CAD;\n\tFri, 31 Aug 2018 11:01:27 +0200 (CEST)",
            "from mail-wm0-f66.google.com (mail-wm0-f66.google.com\n\t[74.125.82.66]) by dpdk.org (Postfix) with ESMTP id 3763D4CB5\n\tfor <dev@dpdk.org>; Fri, 31 Aug 2018 11:01:23 +0200 (CEST)",
            "by mail-wm0-f66.google.com with SMTP id 207-v6so4555493wme.5\n\tfor <dev@dpdk.org>; Fri, 31 Aug 2018 02:01:23 -0700 (PDT)",
            "from 6wind.com (host.78.145.23.62.rev.coltfrance.com.\n\t[62.23.145.78]) by smtp.gmail.com with ESMTPSA id\n\tx16-v6sm13699325wrm.69.2018.08.31.02.01.20\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tFri, 31 Aug 2018 02:01:20 -0700 (PDT)"
        ],
        "References": "<20180803132032.29038-1-adrien.mazarguil@6wind.com>\n\t<20180831085337.21419-1-adrien.mazarguil@6wind.com>",
        "X-Google-Smtp-Source": "ANB0VdYOKtUD0eZZPaNujSiInj3UDasxxxCtxgjiR2YCWGlx/Zc7YNIMJZzkV+Y7zLFaRgS/PCOvvQ==",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to;\n\tbh=uZWaJBCF8DXwsgM3fA8vgZOFwnIey6nXwDh+v4XMXKw=;\n\tb=pGyzWQzVGlm8+rU+p4GKVv9Lx2xMSd4iINaMy7iV8z8wQP7+wKemTj+ishqNNsuE+b\n\tGDUG2whFuKSkSnuw1PdvyR3rvvlOyJ81DlG/9tJ/cP9Yo/hvWwPBGos6kRK6dRvKjqhP\n\te9U/EkLRVTEtFAeM9/oMCcNcOi3Smvt5jh/oMNOXiuBAOjBuCK6ZM2Zg7r9KyonaoKIC\n\toa2I4Nj93R07vcbB+D8BdTsnVsbB7NNvVAzipEaQYH3yDz/8w2VeY9fUfxHWq83cch8l\n\tJ+B5IOliVG0PDPfQ3xgZ/mWKnplKCnirjPU9RKZLmI+L6A2wjQAW9uphDfHuO3syVeBn\n\tH1ow==",
        "MIME-Version": "1.0",
        "X-Received": "by 2002:a1c:be06:: with SMTP id\n\to6-v6mr4090404wmf.65.1535706081383; \n\tFri, 31 Aug 2018 02:01:21 -0700 (PDT)",
        "Message-ID": "<20180831085337.21419-4-adrien.mazarguil@6wind.com>",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to;\n\tbh=uZWaJBCF8DXwsgM3fA8vgZOFwnIey6nXwDh+v4XMXKw=;\n\tb=RvT79YRZwDJ3QDpZTusrEJgHsYUf7rXDvV6kEIhsyY9ZZLUs1X2zqGhtdgYHTAL2un\n\te9uBuiKIsnQn1GOkmYLvcweWlk5NIw94MV+R761OXxNanrN0/hVwEzNyyBeVNg2rS8Tc\n\tDPpB9sezpzImPqyoge4jaOwJPUUYIVfsHvP9e/I/TFLZGoYMtMFVJhYJfGNMRuaZmfYO\n\tuHmq8B7Z5DighMA0O8E9vXP+v7nD7jCSRSfcVcN9gI0m/jsBbha4C7LSMxfm8Znz1OWw\n\tj4M98OlqMRpw8+EnVQFkOdBdfoMIGZXuFwbA0XG7fy3yWhL7fCFZMORUkkKPwhmGk0Vb\n\tQdrA==",
        "Delivered-To": "patchwork@dpdk.org",
        "Precedence": "list",
        "From": "Adrien Mazarguil <adrien.mazarguil@6wind.com>",
        "X-Original-To": "patchwork@dpdk.org",
        "Content-Type": "text/plain; charset=us-ascii",
        "Content-Disposition": "inline",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "To": "Ferruh Yigit <ferruh.yigit@intel.com>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "Date": "Fri, 31 Aug 2018 11:01:05 +0200",
        "X-Gm-Message-State": "APzg51C6TL7TbPrlqb7aPMM5FQEm4zS2DZdYuEHjcElvV2vAetWEFtH9\n\tHKe1SRavRxwPhnYrRBYeWRJ3NINS3JlD9w==",
        "Cc": "dev@dpdk.org, Wenzhuo Lu <wenzhuo.lu@intel.com>,\n\tJingjing Wu <jingjing.wu@intel.com>,\n\tBernard Iremonger <bernard.iremonger@intel.com>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "X-BeenThere": "dev@dpdk.org",
        "Subject": "[dpdk-dev] [PATCH v3 3/7] app/testpmd: rely on flow API conversion\n\tfunction"
    },
    "content": "This commit replaces all local information about pattern items and actions\nas well as flow rule duplication code with calls to rte_flow_conv().\n\nSigned-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>\nCc: Wenzhuo Lu <wenzhuo.lu@intel.com>\nCc: Jingjing Wu <jingjing.wu@intel.com>\nCc: Bernard Iremonger <bernard.iremonger@intel.com>\n---\n app/test-pmd/config.c  | 407 +++++++-------------------------------------\n app/test-pmd/testpmd.h |   7 +-\n 2 files changed, 67 insertions(+), 347 deletions(-)",
    "diff": "diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c\nindex 14ccd6864..669be168b 100644\n--- a/app/test-pmd/config.c\n+++ b/app/test-pmd/config.c\n@@ -984,324 +984,35 @@ port_mtu_set(portid_t port_id, uint16_t mtu)\n \n /* Generic flow management functions. */\n \n-/** Generate flow_item[] entry. */\n-#define MK_FLOW_ITEM(t, s) \\\n-\t[RTE_FLOW_ITEM_TYPE_ ## t] = { \\\n-\t\t.name = # t, \\\n-\t\t.size = s, \\\n-\t}\n-\n-/** Information about known flow pattern items. */\n-static const struct {\n-\tconst char *name;\n-\tsize_t size;\n-} flow_item[] = {\n-\tMK_FLOW_ITEM(END, 0),\n-\tMK_FLOW_ITEM(VOID, 0),\n-\tMK_FLOW_ITEM(INVERT, 0),\n-\tMK_FLOW_ITEM(ANY, sizeof(struct rte_flow_item_any)),\n-\tMK_FLOW_ITEM(PF, 0),\n-\tMK_FLOW_ITEM(VF, sizeof(struct rte_flow_item_vf)),\n-\tMK_FLOW_ITEM(PHY_PORT, sizeof(struct rte_flow_item_phy_port)),\n-\tMK_FLOW_ITEM(PORT_ID, sizeof(struct rte_flow_item_port_id)),\n-\tMK_FLOW_ITEM(RAW, sizeof(struct rte_flow_item_raw)),\n-\tMK_FLOW_ITEM(ETH, sizeof(struct rte_flow_item_eth)),\n-\tMK_FLOW_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),\n-\tMK_FLOW_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),\n-\tMK_FLOW_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),\n-\tMK_FLOW_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),\n-\tMK_FLOW_ITEM(UDP, sizeof(struct rte_flow_item_udp)),\n-\tMK_FLOW_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),\n-\tMK_FLOW_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),\n-\tMK_FLOW_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),\n-\tMK_FLOW_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),\n-\tMK_FLOW_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),\n-\tMK_FLOW_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),\n-\tMK_FLOW_ITEM(GRE, sizeof(struct rte_flow_item_gre)),\n-\tMK_FLOW_ITEM(FUZZY, sizeof(struct rte_flow_item_fuzzy)),\n-\tMK_FLOW_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),\n-\tMK_FLOW_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),\n-\tMK_FLOW_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),\n-\tMK_FLOW_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),\n-\tMK_FLOW_ITEM(VXLAN_GPE, sizeof(struct rte_flow_item_vxlan_gpe)),\n-\tMK_FLOW_ITEM(ARP_ETH_IPV4, sizeof(struct rte_flow_item_arp_eth_ipv4)),\n-\tMK_FLOW_ITEM(IPV6_EXT, sizeof(struct rte_flow_item_ipv6_ext)),\n-\tMK_FLOW_ITEM(ICMP6, sizeof(struct rte_flow_item_icmp6)),\n-\tMK_FLOW_ITEM(ICMP6_ND_NS, sizeof(struct rte_flow_item_icmp6_nd_ns)),\n-\tMK_FLOW_ITEM(ICMP6_ND_NA, sizeof(struct rte_flow_item_icmp6_nd_na)),\n-\tMK_FLOW_ITEM(ICMP6_ND_OPT, sizeof(struct rte_flow_item_icmp6_nd_opt)),\n-\tMK_FLOW_ITEM(ICMP6_ND_OPT_SLA_ETH,\n-\t\t     sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth)),\n-\tMK_FLOW_ITEM(ICMP6_ND_OPT_TLA_ETH,\n-\t\t     sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth)),\n-};\n-\n-/** Pattern item specification types. */\n-enum item_spec_type {\n-\tITEM_SPEC,\n-\tITEM_LAST,\n-\tITEM_MASK,\n-};\n-\n-/** Compute storage space needed by item specification and copy it. */\n-static size_t\n-flow_item_spec_copy(void *buf, const struct rte_flow_item *item,\n-\t\t    enum item_spec_type type)\n-{\n-\tsize_t size = 0;\n-\tconst void *data =\n-\t\ttype == ITEM_SPEC ? item->spec :\n-\t\ttype == ITEM_LAST ? item->last :\n-\t\ttype == ITEM_MASK ? item->mask :\n-\t\tNULL;\n-\n-\tif (!item->spec || !data)\n-\t\tgoto empty;\n-\tswitch (item->type) {\n-\t\tunion {\n-\t\t\tconst struct rte_flow_item_raw *raw;\n-\t\t} spec;\n-\t\tunion {\n-\t\t\tconst struct rte_flow_item_raw *raw;\n-\t\t} last;\n-\t\tunion {\n-\t\t\tconst struct rte_flow_item_raw *raw;\n-\t\t} mask;\n-\t\tunion {\n-\t\t\tconst struct rte_flow_item_raw *raw;\n-\t\t} src;\n-\t\tunion {\n-\t\t\tstruct rte_flow_item_raw *raw;\n-\t\t} dst;\n-\t\tsize_t off;\n-\n-\tcase RTE_FLOW_ITEM_TYPE_RAW:\n-\t\tspec.raw = item->spec;\n-\t\tlast.raw = item->last ? item->last : item->spec;\n-\t\tmask.raw = item->mask ? item->mask : &rte_flow_item_raw_mask;\n-\t\tsrc.raw = data;\n-\t\tdst.raw = buf;\n-\t\toff = RTE_ALIGN_CEIL(sizeof(struct rte_flow_item_raw),\n-\t\t\t\t     sizeof(*src.raw->pattern));\n-\t\tif (type == ITEM_SPEC ||\n-\t\t    (type == ITEM_MASK &&\n-\t\t     ((spec.raw->length & mask.raw->length) >=\n-\t\t      (last.raw->length & mask.raw->length))))\n-\t\t\tsize = spec.raw->length & mask.raw->length;\n-\t\telse\n-\t\t\tsize = last.raw->length & mask.raw->length;\n-\t\tsize = off + size * sizeof(*src.raw->pattern);\n-\t\tif (dst.raw) {\n-\t\t\tmemcpy(dst.raw, src.raw, sizeof(*src.raw));\n-\t\t\tdst.raw->pattern = memcpy((uint8_t *)dst.raw + off,\n-\t\t\t\t\t\t  src.raw->pattern,\n-\t\t\t\t\t\t  size - off);\n-\t\t}\n-\t\tbreak;\n-\tdefault:\n-\t\tsize = flow_item[item->type].size;\n-\t\tif (buf)\n-\t\t\tmemcpy(buf, data, size);\n-\t\tbreak;\n-\t}\n-empty:\n-\treturn RTE_ALIGN_CEIL(size, sizeof(double));\n-}\n-\n-/** Generate flow_action[] entry. */\n-#define MK_FLOW_ACTION(t, s) \\\n-\t[RTE_FLOW_ACTION_TYPE_ ## t] = { \\\n-\t\t.name = # t, \\\n-\t\t.size = s, \\\n-\t}\n-\n-/** Information about known flow actions. */\n-static const struct {\n-\tconst char *name;\n-\tsize_t size;\n-} flow_action[] = {\n-\tMK_FLOW_ACTION(END, 0),\n-\tMK_FLOW_ACTION(VOID, 0),\n-\tMK_FLOW_ACTION(PASSTHRU, 0),\n-\tMK_FLOW_ACTION(MARK, sizeof(struct rte_flow_action_mark)),\n-\tMK_FLOW_ACTION(FLAG, 0),\n-\tMK_FLOW_ACTION(QUEUE, sizeof(struct rte_flow_action_queue)),\n-\tMK_FLOW_ACTION(DROP, 0),\n-\tMK_FLOW_ACTION(COUNT, sizeof(struct rte_flow_action_count)),\n-\tMK_FLOW_ACTION(RSS, sizeof(struct rte_flow_action_rss)),\n-\tMK_FLOW_ACTION(PF, 0),\n-\tMK_FLOW_ACTION(VF, sizeof(struct rte_flow_action_vf)),\n-\tMK_FLOW_ACTION(PHY_PORT, sizeof(struct rte_flow_action_phy_port)),\n-\tMK_FLOW_ACTION(PORT_ID, sizeof(struct rte_flow_action_port_id)),\n-\tMK_FLOW_ACTION(METER, sizeof(struct rte_flow_action_meter)),\n-\tMK_FLOW_ACTION(OF_SET_MPLS_TTL,\n-\t\t       sizeof(struct rte_flow_action_of_set_mpls_ttl)),\n-\tMK_FLOW_ACTION(OF_DEC_MPLS_TTL, 0),\n-\tMK_FLOW_ACTION(OF_SET_NW_TTL,\n-\t\t       sizeof(struct rte_flow_action_of_set_nw_ttl)),\n-\tMK_FLOW_ACTION(OF_DEC_NW_TTL, 0),\n-\tMK_FLOW_ACTION(OF_COPY_TTL_OUT, 0),\n-\tMK_FLOW_ACTION(OF_COPY_TTL_IN, 0),\n-\tMK_FLOW_ACTION(OF_POP_VLAN, 0),\n-\tMK_FLOW_ACTION(OF_PUSH_VLAN,\n-\t\t       sizeof(struct rte_flow_action_of_push_vlan)),\n-\tMK_FLOW_ACTION(OF_SET_VLAN_VID,\n-\t\t       sizeof(struct rte_flow_action_of_set_vlan_vid)),\n-\tMK_FLOW_ACTION(OF_SET_VLAN_PCP,\n-\t\t       sizeof(struct rte_flow_action_of_set_vlan_pcp)),\n-\tMK_FLOW_ACTION(OF_POP_MPLS,\n-\t\t       sizeof(struct rte_flow_action_of_pop_mpls)),\n-\tMK_FLOW_ACTION(OF_PUSH_MPLS,\n-\t\t       sizeof(struct rte_flow_action_of_push_mpls)),\n-};\n-\n-/** Compute storage space needed by action configuration and copy it. */\n-static size_t\n-flow_action_conf_copy(void *buf, const struct rte_flow_action *action)\n-{\n-\tsize_t size = 0;\n-\n-\tif (!action->conf)\n-\t\tgoto empty;\n-\tswitch (action->type) {\n-\t\tunion {\n-\t\t\tconst struct rte_flow_action_rss *rss;\n-\t\t} src;\n-\t\tunion {\n-\t\t\tstruct rte_flow_action_rss *rss;\n-\t\t} dst;\n-\t\tsize_t off;\n-\n-\tcase RTE_FLOW_ACTION_TYPE_RSS:\n-\t\tsrc.rss = action->conf;\n-\t\tdst.rss = buf;\n-\t\toff = 0;\n-\t\tif (dst.rss)\n-\t\t\t*dst.rss = (struct rte_flow_action_rss){\n-\t\t\t\t.func = src.rss->func,\n-\t\t\t\t.level = src.rss->level,\n-\t\t\t\t.types = src.rss->types,\n-\t\t\t\t.key_len = src.rss->key_len,\n-\t\t\t\t.queue_num = src.rss->queue_num,\n-\t\t\t};\n-\t\toff += sizeof(*src.rss);\n-\t\tif (src.rss->key_len) {\n-\t\t\toff = RTE_ALIGN_CEIL(off, sizeof(double));\n-\t\t\tsize = sizeof(*src.rss->key) * src.rss->key_len;\n-\t\t\tif (dst.rss)\n-\t\t\t\tdst.rss->key = memcpy\n-\t\t\t\t\t((void *)((uintptr_t)dst.rss + off),\n-\t\t\t\t\t src.rss->key, size);\n-\t\t\toff += size;\n-\t\t}\n-\t\tif (src.rss->queue_num) {\n-\t\t\toff = RTE_ALIGN_CEIL(off, sizeof(double));\n-\t\t\tsize = sizeof(*src.rss->queue) * src.rss->queue_num;\n-\t\t\tif (dst.rss)\n-\t\t\t\tdst.rss->queue = memcpy\n-\t\t\t\t\t((void *)((uintptr_t)dst.rss + off),\n-\t\t\t\t\t src.rss->queue, size);\n-\t\t\toff += size;\n-\t\t}\n-\t\tsize = off;\n-\t\tbreak;\n-\tdefault:\n-\t\tsize = flow_action[action->type].size;\n-\t\tif (buf)\n-\t\t\tmemcpy(buf, action->conf, size);\n-\t\tbreak;\n-\t}\n-empty:\n-\treturn RTE_ALIGN_CEIL(size, sizeof(double));\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 \t      const struct rte_flow_item *pattern,\n-\t      const struct rte_flow_action *actions)\n-{\n-\tconst struct rte_flow_item *item;\n-\tconst struct rte_flow_action *action;\n-\tstruct port_flow *pf = NULL;\n-\tsize_t tmp;\n-\tsize_t off1 = 0;\n-\tsize_t off2 = 0;\n-\tint err = ENOTSUP;\n-\n-store:\n-\titem = pattern;\n-\tif (pf)\n-\t\tpf->pattern = (void *)&pf->data[off1];\n-\tdo {\n-\t\tstruct rte_flow_item *dst = NULL;\n-\n-\t\tif ((unsigned int)item->type >= RTE_DIM(flow_item) ||\n-\t\t    !flow_item[item->type].name)\n-\t\t\tgoto notsup;\n-\t\tif (pf)\n-\t\t\tdst = memcpy(pf->data + off1, item, sizeof(*item));\n-\t\toff1 += sizeof(*item);\n-\t\tif (item->spec) {\n-\t\t\tif (pf)\n-\t\t\t\tdst->spec = pf->data + off2;\n-\t\t\toff2 += flow_item_spec_copy\n-\t\t\t\t(pf ? pf->data + off2 : NULL, item, ITEM_SPEC);\n-\t\t}\n-\t\tif (item->last) {\n-\t\t\tif (pf)\n-\t\t\t\tdst->last = pf->data + off2;\n-\t\t\toff2 += flow_item_spec_copy\n-\t\t\t\t(pf ? pf->data + off2 : NULL, item, ITEM_LAST);\n-\t\t}\n-\t\tif (item->mask) {\n-\t\t\tif (pf)\n-\t\t\t\tdst->mask = pf->data + off2;\n-\t\t\toff2 += flow_item_spec_copy\n-\t\t\t\t(pf ? pf->data + off2 : NULL, item, ITEM_MASK);\n-\t\t}\n-\t\toff2 = RTE_ALIGN_CEIL(off2, sizeof(double));\n-\t} while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);\n-\toff1 = RTE_ALIGN_CEIL(off1, sizeof(double));\n-\taction = actions;\n-\tif (pf)\n-\t\tpf->actions = (void *)&pf->data[off1];\n-\tdo {\n-\t\tstruct rte_flow_action *dst = NULL;\n-\n-\t\tif ((unsigned int)action->type >= RTE_DIM(flow_action) ||\n-\t\t    !flow_action[action->type].name)\n-\t\t\tgoto notsup;\n-\t\tif (pf)\n-\t\t\tdst = memcpy(pf->data + off1, action, sizeof(*action));\n-\t\toff1 += sizeof(*action);\n-\t\tif (action->conf) {\n-\t\t\tif (pf)\n-\t\t\t\tdst->conf = pf->data + off2;\n-\t\t\toff2 += flow_action_conf_copy\n-\t\t\t\t(pf ? pf->data + off2 : NULL, action);\n-\t\t}\n-\t\toff2 = RTE_ALIGN_CEIL(off2, sizeof(double));\n-\t} while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);\n-\tif (pf != NULL)\n+\t      const struct rte_flow_action *actions,\n+\t      struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_conv_rule rule = {\n+\t\t.attr_ro = attr,\n+\t\t.pattern_ro = pattern,\n+\t\t.actions_ro = actions,\n+\t};\n+\tstruct port_flow *pf;\n+\tint ret;\n+\n+\tret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &rule, error);\n+\tif (ret < 0)\n+\t\treturn NULL;\n+\tpf = calloc(1, offsetof(struct port_flow, rule) + ret);\n+\tif (!pf) {\n+\t\trte_flow_error_set\n+\t\t\t(error, errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t \"calloc() failed\");\n+\t\treturn NULL;\n+\t}\n+\tif (rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &pf->rule, ret, &rule,\n+\t\t\t  error) >= 0)\n \t\treturn pf;\n-\toff1 = RTE_ALIGN_CEIL(off1, sizeof(double));\n-\ttmp = RTE_ALIGN_CEIL(offsetof(struct port_flow, data), sizeof(double));\n-\tpf = calloc(1, tmp + off1 + off2);\n-\tif (pf == NULL)\n-\t\terr = errno;\n-\telse {\n-\t\t*pf = (const struct port_flow){\n-\t\t\t.size = tmp + off1 + off2,\n-\t\t\t.attr = *attr,\n-\t\t};\n-\t\ttmp -= offsetof(struct port_flow, data);\n-\t\toff2 = tmp + off1;\n-\t\toff1 = tmp;\n-\t\tgoto store;\n-\t}\n-notsup:\n-\trte_errno = err;\n+\tfree(pf);\n \treturn NULL;\n }\n \n@@ -1391,13 +1102,10 @@ port_flow_create(portid_t port_id,\n \t\tid = port->flow_list->id + 1;\n \t} else\n \t\tid = 0;\n-\tpf = port_flow_new(attr, pattern, actions);\n+\tpf = port_flow_new(attr, pattern, actions, &error);\n \tif (!pf) {\n-\t\tint err = rte_errno;\n-\n-\t\tprintf(\"Cannot allocate flow: %s\\n\", rte_strerror(err));\n \t\trte_flow_destroy(port_id, flow, NULL);\n-\t\treturn -err;\n+\t\treturn port_flow_complain(&error);\n \t}\n \tpf->next = port->flow_list;\n \tpf->id = id;\n@@ -1489,6 +1197,7 @@ port_flow_query(portid_t port_id, uint32_t rule,\n \tunion {\n \t\tstruct rte_flow_query_count count;\n \t} query;\n+\tint ret;\n \n \tif (port_id_is_invalid(port_id, ENABLED_WARN) ||\n \t    port_id == (portid_t)RTE_PORT_ALL)\n@@ -1501,11 +1210,10 @@ port_flow_query(portid_t port_id, uint32_t rule,\n \t\tprintf(\"Flow rule #%u not found\\n\", rule);\n \t\treturn -ENOENT;\n \t}\n-\tif ((unsigned int)action->type >= RTE_DIM(flow_action) ||\n-\t    !flow_action[action->type].name)\n-\t\tname = \"unknown\";\n-\telse\n-\t\tname = flow_action[action->type].name;\n+\tret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,\n+\t\t\t    &name, sizeof(name), action, &error);\n+\tif (ret < 0)\n+\t\treturn port_flow_complain(&error);\n \tswitch (action->type) {\n \tcase RTE_FLOW_ACTION_TYPE_COUNT:\n \t\tbreak;\n@@ -1558,48 +1266,63 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])\n \t/* Sort flows by group, priority and ID. */\n \tfor (pf = port->flow_list; pf != NULL; pf = pf->next) {\n \t\tstruct port_flow **tmp;\n+\t\tconst struct rte_flow_attr *curr = pf->rule.attr;\n \n \t\tif (n) {\n \t\t\t/* Filter out unwanted groups. */\n \t\t\tfor (i = 0; i != n; ++i)\n-\t\t\t\tif (pf->attr.group == group[i])\n+\t\t\t\tif (curr->group == group[i])\n \t\t\t\t\tbreak;\n \t\t\tif (i == n)\n \t\t\t\tcontinue;\n \t\t}\n-\t\ttmp = &list;\n-\t\twhile (*tmp &&\n-\t\t       (pf->attr.group > (*tmp)->attr.group ||\n-\t\t\t(pf->attr.group == (*tmp)->attr.group &&\n-\t\t\t pf->attr.priority > (*tmp)->attr.priority) ||\n-\t\t\t(pf->attr.group == (*tmp)->attr.group &&\n-\t\t\t pf->attr.priority == (*tmp)->attr.priority &&\n-\t\t\t pf->id > (*tmp)->id)))\n-\t\t\ttmp = &(*tmp)->tmp;\n+\t\tfor (tmp = &list; *tmp; tmp = &(*tmp)->tmp) {\n+\t\t\tconst struct rte_flow_attr *comp = (*tmp)->rule.attr;\n+\n+\t\t\tif (curr->group > comp->group ||\n+\t\t\t    (curr->group == comp->group &&\n+\t\t\t     curr->priority > comp->priority) ||\n+\t\t\t    (curr->group == comp->group &&\n+\t\t\t     curr->priority == comp->priority &&\n+\t\t\t     pf->id > (*tmp)->id))\n+\t\t\t\tcontinue;\n+\t\t\tbreak;\n+\t\t}\n \t\tpf->tmp = *tmp;\n \t\t*tmp = pf;\n \t}\n \tprintf(\"ID\\tGroup\\tPrio\\tAttr\\tRule\\n\");\n \tfor (pf = list; pf != NULL; pf = pf->tmp) {\n-\t\tconst struct rte_flow_item *item = pf->pattern;\n-\t\tconst struct rte_flow_action *action = pf->actions;\n+\t\tconst struct rte_flow_item *item = pf->rule.pattern;\n+\t\tconst struct rte_flow_action *action = pf->rule.actions;\n+\t\tconst char *name;\n \n \t\tprintf(\"%\" PRIu32 \"\\t%\" PRIu32 \"\\t%\" PRIu32 \"\\t%c%c%c\\t\",\n \t\t       pf->id,\n-\t\t       pf->attr.group,\n-\t\t       pf->attr.priority,\n-\t\t       pf->attr.ingress ? 'i' : '-',\n-\t\t       pf->attr.egress ? 'e' : '-',\n-\t\t       pf->attr.transfer ? 't' : '-');\n+\t\t       pf->rule.attr->group,\n+\t\t       pf->rule.attr->priority,\n+\t\t       pf->rule.attr->ingress ? 'i' : '-',\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\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+\t\t\t\tname = \"[UNKNOWN]\";\n \t\t\tif (item->type != RTE_FLOW_ITEM_TYPE_VOID)\n-\t\t\t\tprintf(\"%s \", flow_item[item->type].name);\n+\t\t\t\tprintf(\"%s \", name);\n \t\t\t++item;\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\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)\n+\t\t\t\tname = \"[UNKNOWN]\";\n \t\t\tif (action->type != RTE_FLOW_ACTION_TYPE_VOID)\n-\t\t\t\tprintf(\" %s\", flow_action[action->type].name);\n+\t\t\t\tprintf(\" %s\", name);\n \t\t\t++action;\n \t\t}\n \t\tprintf(\"\\n\");\ndiff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h\nindex a1f661472..11afb487f 100644\n--- a/app/test-pmd/testpmd.h\n+++ b/app/test-pmd/testpmd.h\n@@ -124,15 +124,12 @@ struct fwd_stream {\n \n /** Descriptor for a single flow. */\n struct port_flow {\n-\tsize_t size; /**< Allocated space including data[]. */\n \tstruct port_flow *next; /**< Next flow in list. */\n \tstruct port_flow *tmp; /**< Temporary linking. */\n \tuint32_t id; /**< Flow rule ID. */\n \tstruct rte_flow *flow; /**< Opaque flow object returned by PMD. */\n-\tstruct rte_flow_attr attr; /**< Attributes. */\n-\tstruct rte_flow_item *pattern; /**< Pattern. */\n-\tstruct rte_flow_action *actions; /**< Actions. */\n-\tuint8_t data[]; /**< Storage for pattern/actions. */\n+\tstruct rte_flow_conv_rule rule; /* Saved flow rule description. */\n+\tuint8_t data[]; /**< Storage for flow rule description */\n };\n \n #ifdef SOFTNIC\n",
    "prefixes": [
        "v3",
        "3/7"
    ]
}