get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 41343,
    "url": "http://patches.dpdk.org/api/patches/41343/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/15e22f72e9b4c56e79809c413ce3001e4f6067d8.1529565844.git.nelio.laranjeiro@6wind.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": "<15e22f72e9b4c56e79809c413ce3001e4f6067d8.1529565844.git.nelio.laranjeiro@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/15e22f72e9b4c56e79809c413ce3001e4f6067d8.1529565844.git.nelio.laranjeiro@6wind.com",
    "date": "2018-06-21T07:25:02",
    "name": "[v3] ethdev: add flow API to expand RSS flows",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "575d453e0e500384ff9b42e51a90767ddc7a642e",
    "submitter": {
        "id": 243,
        "url": "http://patches.dpdk.org/api/people/243/?format=api",
        "name": "Nélio Laranjeiro",
        "email": "nelio.laranjeiro@6wind.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/15e22f72e9b4c56e79809c413ce3001e4f6067d8.1529565844.git.nelio.laranjeiro@6wind.com/mbox/",
    "series": [
        {
            "id": 186,
            "url": "http://patches.dpdk.org/api/series/186/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=186",
            "date": "2018-06-21T07:25:02",
            "name": "[v3] ethdev: add flow API to expand RSS flows",
            "version": 3,
            "mbox": "http://patches.dpdk.org/series/186/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/41343/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/41343/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 014951BB20;\n\tThu, 21 Jun 2018 09:24:59 +0200 (CEST)",
            "from mail-wm0-f67.google.com (mail-wm0-f67.google.com\n\t[74.125.82.67]) by dpdk.org (Postfix) with ESMTP id 0A0DA1BB1C\n\tfor <dev@dpdk.org>; Thu, 21 Jun 2018 09:24:58 +0200 (CEST)",
            "by mail-wm0-f67.google.com with SMTP id p11-v6so3881125wmc.4\n\tfor <dev@dpdk.org>; Thu, 21 Jun 2018 00:24:57 -0700 (PDT)",
            "from laranjeiro-vm.dev.6wind.com\n\t(host.78.145.23.62.rev.coltfrance.com. [62.23.145.78])\n\tby smtp.gmail.com with ESMTPSA id\n\tm10-v6sm5821907wrq.56.2018.06.21.00.24.56\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tThu, 21 Jun 2018 00:24:56 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=from:to:subject:date:message-id:in-reply-to:references;\n\tbh=3gYti5iutHVY+p+b2eG4iwWU0XQ4qaqGQnECd1BhKEU=;\n\tb=zITNVj9Dx55mDGZEz1XPnUnG+Yp3z44z4agobX7L4iYc3hfAfZ2IQ0ZUf3K9FEFCx0\n\tvJFlFhbuQmZXrOTQbF3vNG4wbWhErNh0JiexLI9S7L0NPDAIJuC4NJWaBCWK3Vc5IYAP\n\twixyU8G/HkOwqyhzsSGFojGZ+PwJL95PVcHam2zA53nMNOrgPKoXbwWQbRFG4hkADu4b\n\t58m4AICzxtqUHotPyK71a8q0w4ZtWmewLz2kkF5R/VS+0z74oYQ5LM34fjMEpQssbLJo\n\tbhTza8Qta9Ew2Mo8z8ZRubmmVO1cXi3mcXDKPt94v74qVJTgH1S5rc1YFL7QC93TBjwe\n\ttfBw==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=3gYti5iutHVY+p+b2eG4iwWU0XQ4qaqGQnECd1BhKEU=;\n\tb=daHezhApH4Csl+anmmZDEq1FyQyNaAAKh2Conlf2/Hh+kJJw+dXx83sQb+lzG+cnPZ\n\tML7ICuPpp4faafuCoEvEKzP4QxHTQsMao6XQJGy0TWCVRl4oUgw9hiX0BUzhetXtKaA+\n\tCfHCCWcIT38S7KIr3SS8wjNLWDlnrzwbw3TQlitaBv8EJXJAWsL8Y+5aeAsXgTh/0wDz\n\t6+teT4FQ3PtIRDbM8X9qLRA42EY/iRsgMcIQQ85R3xsUDFZ1Aw1IMofDaag36ATeDYpY\n\t/lUWdt9VUHufoI7VNbFRyee0PZPS57QkOL7ucnQuSsoFAupsUSMUvYdSWT0GVcDo3ucF\n\tTrDw==",
        "X-Gm-Message-State": "APt69E1Tz9dZP8+Q0M1wvnFyj9GSQQswv6NRE9BiXTOX8bNrGsMG/bmq\n\tpi6273Q8nQk0IE0bK/2tUGcBsHYbdQ==",
        "X-Google-Smtp-Source": "ADUXVKI3//fywxCUD8icuqTCccvYgt8ZkeCwO3QSIE98KHvG1LG1wqnbY9bOltrAB8ZboUT5N5d+2A==",
        "X-Received": "by 2002:a1c:8c55:: with SMTP id\n\to82-v6mr3843304wmd.60.1529565897283; \n\tThu, 21 Jun 2018 00:24:57 -0700 (PDT)",
        "From": "Nelio Laranjeiro <nelio.laranjeiro@6wind.com>",
        "To": "dev@dpdk.org,\n\tAdrien Mazarguil <adrien.mazarguil@6wind.com>",
        "Date": "Thu, 21 Jun 2018 09:25:02 +0200",
        "Message-Id": "<15e22f72e9b4c56e79809c413ce3001e4f6067d8.1529565844.git.nelio.laranjeiro@6wind.com>",
        "X-Mailer": "git-send-email 2.18.0.rc2",
        "In-Reply-To": "<3c31112367e8d44d1568afbf52de20c6c9ff0c9c.1528187101.git.nelio.laranjeiro@6wind.com>",
        "References": "<3c31112367e8d44d1568afbf52de20c6c9ff0c9c.1528187101.git.nelio.laranjeiro@6wind.com>",
        "Subject": "[dpdk-dev] [PATCH v3] ethdev: add flow API to expand RSS flows",
        "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\t<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\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Introduce an helper for PMD to expand easily flows items list with RSS\naction into multiple flow items lists with priority information.\n\nFor instance a user items list being \"eth / end\" with rss action types\n\"ipv4-udp ipv6-udp end\" needs to be expanded into three items lists:\n\n - eth\n - eth / ipv4 / udp\n - eth / ipv6 / udp\n\nto match the user request.  Some drivers are unable to reach such\nrequest without this expansion, this API is there to help those.\nOnly PMD should use such API for their internal cooking, the application\nwill still handle a single flow.\n\nSigned-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>\n\n---\n\nChanges in v3:\n\n- Fix a segmentation fault due to an uninitialized pointer.\n\nChanges in v2:\n\n- Fix expansion for UDP/TCP layers where L3 may not be in the original\n  items list and thus is missing in the expansion.\n- Fix size verification for some layers causing a segfault\n---\n lib/librte_ethdev/rte_flow.c        | 408 ++++++++++++++++++++++++++++\n lib/librte_ethdev/rte_flow_driver.h |  32 +++\n 2 files changed, 440 insertions(+)",
    "diff": "diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c\nindex b2afba089..9d86c20cb 100644\n--- a/lib/librte_ethdev/rte_flow.c\n+++ b/lib/librte_ethdev/rte_flow.c\n@@ -526,3 +526,411 @@ rte_flow_copy(struct rte_flow_desc *desc, size_t len,\n \t}\n \treturn 0;\n }\n+\n+/* Copy the existing items list and expand with new items. */\n+static int\n+rte_flow_expand_rss_item(void *buf, size_t size,\n+\t\t\t const struct rte_flow_item *items,\n+\t\t\t const struct rte_flow_item *newitems)\n+{\n+\tvoid *data = buf;\n+\tconst struct rte_flow_item *item;\n+\tstruct rte_flow_item *dst;\n+\tsize_t data_size = 0;\n+\n+\tdst = data;\n+\t/* Copy Item structure into buffer. */\n+\tfor (item = items; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {\n+\t\tif (item->type == RTE_FLOW_ITEM_TYPE_VOID)\n+\t\t\tcontinue;\n+\t\tif (data_size + sizeof(*item) <= size) {\n+\t\t\tmemcpy(dst, item, sizeof(*item));\n+\t\t\t++dst;\n+\t\t}\n+\t\tdata_size += sizeof(*item);\n+\t}\n+\titem = newitems;\n+\tdo {\n+\t\tif (item->type == RTE_FLOW_ITEM_TYPE_VOID) {\n+\t\t\t++item;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (data_size + sizeof(*item) <= size) {\n+\t\t\tmemcpy(dst, item, sizeof(*item));\n+\t\t\t++dst;\n+\t\t}\n+\t\tdata_size += sizeof(*item);\n+\t\t++item;\n+\t} while ((item - 1)->type != RTE_FLOW_ITEM_TYPE_END);\n+\t/**\n+\t * Copy Item spec, last, mask into buffer and set pointers\n+\t * accordingly.\n+\t */\n+\tdst = data;\n+\tfor (item = items; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {\n+\t\tif (item->type == RTE_FLOW_ITEM_TYPE_VOID)\n+\t\t\tcontinue;\n+\t\tif (item->spec) {\n+\t\t\tsize_t s = flow_item_spec_copy(NULL, item, ITEM_SPEC);\n+\t\t\tvoid *addr = (data_size + s) <= size ?\n+\t\t\t\t(void *)((uintptr_t)data + data_size) :\n+\t\t\t\tNULL;\n+\n+\t\t\tdata_size += flow_item_spec_copy(addr, item, ITEM_SPEC);\n+\t\t\tif (addr)\n+\t\t\t\tdst->spec = addr;\n+\t\t}\n+\t\tif (item->last) {\n+\t\t\tsize_t s = flow_item_spec_copy(NULL, item, ITEM_LAST);\n+\t\t\tvoid *addr = (data_size + s) <= size ?\n+\t\t\t\t(void *)((uintptr_t)data + data_size) :\n+\t\t\t\tNULL;\n+\n+\t\t\tdata_size += flow_item_spec_copy(addr, item, ITEM_LAST);\n+\t\t\tif (addr)\n+\t\t\t\tdst->last = addr;\n+\t\t}\n+\t\tif (item->mask) {\n+\t\t\tsize_t s = flow_item_spec_copy(NULL, item, ITEM_MASK);\n+\t\t\tvoid *addr = (data_size + s) <= size ?\n+\t\t\t\t(void *)((uintptr_t)data + data_size) :\n+\t\t\t\tNULL;\n+\n+\t\t\tdata_size += flow_item_spec_copy(addr, item, ITEM_MASK);\n+\t\t\tif (addr)\n+\t\t\t\tdst->mask = addr;\n+\t\t}\n+\t\tif (data_size <= size)\n+\t\t\t++dst;\n+\t}\n+\treturn data_size;\n+}\n+\n+/** Verify the expansion is supported by the device. */\n+static int\n+rte_flow_expand_rss_is_supported(const enum rte_flow_item_type **supported,\n+\t\t\t\t const enum rte_flow_item_type *expand)\n+{\n+\tunsigned int i;\n+\tunsigned int sidx;\n+\tunsigned int eidx;\n+\n+\tfor (i = 0; supported[i]; ++i) {\n+\t\tsidx = 0;\n+\t\teidx = 0;\n+\t\twhile (1) {\n+\t\t\tif (expand[eidx] != supported[i][sidx]) {\n+\t\t\t\tbreak;\n+\t\t\t} else if ((expand[eidx] == RTE_FLOW_ITEM_TYPE_END) &&\n+\t\t\t\t   (supported[i][sidx] ==\n+\t\t\t\t    RTE_FLOW_ITEM_TYPE_END)) {\n+\t\t\t\treturn 1;\n+\t\t\t} else if ((expand[eidx] == RTE_FLOW_ITEM_TYPE_END) ||\n+\t\t\t\t   (supported[i][sidx] ==\n+\t\t\t\t    RTE_FLOW_ITEM_TYPE_END)) {\n+\t\t\t\tbreak;\n+\t\t\t} else if (expand[eidx] == RTE_FLOW_ITEM_TYPE_VOID) {\n+\t\t\t\t++eidx;\n+\t\t\t\tcontinue;\n+\t\t\t} else if (supported[i][sidx] ==\n+\t\t\t\t   RTE_FLOW_ITEM_TYPE_VOID) {\n+\t\t\t\t++sidx;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\t++sidx;\n+\t\t\t++eidx;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+/** Update internal buffer. */\n+static inline void\n+rte_flow_expand_rss_update(struct rte_flow_expand_rss *buf, void *addr,\n+\t\t\t   uint32_t priority)\n+{\n+\tbuf->priority[buf->entries] = priority;\n+\tbuf->patterns[buf->entries] = addr;\n+\tbuf->entries++;\n+}\n+\n+int\n+rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size,\n+\t\t    const struct rte_flow_item *pat, uint64_t types,\n+\t\t    const enum rte_flow_item_type **supported)\n+{\n+\tconst struct rte_flow_item *item;\n+\tuint32_t priority = 0;\n+\tstruct {\n+\t\tuint32_t eth:1; /**< Ethernet item is  present. */\n+\t\tuint32_t ipv4:1; /**< IPv4 item is  present. */\n+\t\tuint32_t ipv6:1; /**< IPv6 item is  present. */\n+\t\tuint32_t ipv6_ex:1; /**< IPv6 EXT item is  present. */\n+\t\tuint32_t udp:1; /**< UDP item is  present. */\n+\t\tuint32_t tcp:1; /**< TCP item is  present. */\n+\t\tuint32_t sctp:1; /**< STCP item is  present. */\n+\t\tuint32_t vxlan:1; /**< VXLAN item is  present. */\n+\t\tuint32_t geneve:1; /**< GENEVE item is  present. */\n+\t\tuint32_t nvgre:1; /**< NVGRE item is  present. */\n+\t} layer = { .eth = 0 };\n+\tconst struct rte_flow_item end[] = {\n+\t\t{ .type = RTE_FLOW_ITEM_TYPE_END },\n+\t};\n+\tvoid *addr = NULL;\n+\tuint32_t off; /**< Offset to write new items data starting from *buf. */\n+\tuint32_t max_entries;\n+\n+\tfor (max_entries = 0; supported[max_entries]; ++max_entries)\n+\t\t;\n+\toff = sizeof(*buf) +\n+\t\t/* Size for the list of patterns. */\n+\t\tsizeof(*buf->patterns) +\n+\t\tRTE_ALIGN_CEIL(max_entries * sizeof(struct rte_flow_item *),\n+\t\t\t       sizeof(void *)) +\n+\t\t/* Size for priorities. */\n+\t\tsizeof(*buf->priority) +\n+\t\tRTE_ALIGN_CEIL(max_entries * sizeof(uint32_t), sizeof(void *));\n+\tif (off < size) {\n+\t\tbuf->priority = (void *)(buf + 1);\n+\t\tbuf->patterns = (void *)&buf->priority[max_entries];\n+\t\tbuf->patterns[0] = (void *)&buf->patterns[max_entries];\n+\t\taddr = buf->patterns[0];\n+\t\tbuf->entries = 0;\n+\t}\n+\t/**\n+\t * Parse the pattern and deactivate the bit-field in RSS which cannot\n+\t * match anymore the pattern.\n+\t */\n+\tfor (item = pat; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\tlayer.eth = 1;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tlayer.ipv4 = 1;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n+\t\t\tlayer.ipv6 = 1;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6_EXT:\n+\t\t\tlayer.ipv6_ex = 1;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tlayer.udp = 1;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\t\tlayer.tcp = 1;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\t\tlayer.vxlan = 1;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_GENEVE:\n+\t\t\tlayer.geneve = 1;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_NVGRE:\n+\t\t\tlayer.nvgre = 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\toff += rte_flow_expand_rss_item(addr, (off < size) ? size - off : 0,\n+\t\t\t\t\tpat, end);\n+\tif (off <= size) {\n+\t\trte_flow_expand_rss_update(buf, addr, priority);\n+\t\taddr = (void *)((uintptr_t)buf + off);\n+\t}\n+\tif ((types & ETH_RSS_IP) &&\n+\t    (!(layer.ipv4 || layer.ipv6 || layer.ipv6_ex))) {\n+\t\t++priority;\n+\t\tif (types & (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |\n+\t\t\t     ETH_RSS_NONFRAG_IPV4_OTHER)) {\n+\t\t\tconst struct rte_flow_item new[] = {\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_IPV4 },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_END },\n+\t\t\t};\n+\t\t\tconst enum rte_flow_item_type list[] = {\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_ETH,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_END,\n+\t\t\t};\n+\t\t\tint ret;\n+\n+\t\t\tret = rte_flow_expand_rss_is_supported(supported, list);\n+\t\t\tif (ret) {\n+\t\t\t\toff += rte_flow_expand_rss_item\n+\t\t\t\t\t(addr, (off <= size) ? size - off : 0,\n+\t\t\t\t\t pat, new);\n+\t\t\t\tif (off <= size) {\n+\t\t\t\t\trte_flow_expand_rss_update(buf, addr,\n+\t\t\t\t\t\t\t\t   priority);\n+\t\t\t\t\taddr = (void *)((uintptr_t)buf + off);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif (types & (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 |\n+\t\t\t     ETH_RSS_NONFRAG_IPV6_OTHER)) {\n+\t\t\tconst struct rte_flow_item new[] = {\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_IPV6 },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_END },\n+\t\t\t};\n+\t\t\tconst enum rte_flow_item_type list[] = {\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_ETH,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_END,\n+\t\t\t};\n+\t\t\tint ret;\n+\n+\t\t\tret = rte_flow_expand_rss_is_supported(supported, list);\n+\t\t\tif (ret) {\n+\t\t\t\toff += rte_flow_expand_rss_item\n+\t\t\t\t\t(addr, (off <= size) ? size - off : 0,\n+\t\t\t\t\t pat, new);\n+\t\t\t\tif (off <= size) {\n+\t\t\t\t\trte_flow_expand_rss_update(buf, addr,\n+\t\t\t\t\t\t\t\t   priority);\n+\t\t\t\t\taddr = (void *)((uintptr_t)buf + off);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif (types & ETH_RSS_IPV6_EX) {\n+\t\t\tconst struct rte_flow_item new[] = {\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_IPV6_EXT },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_END },\n+\t\t\t};\n+\t\t\tconst enum rte_flow_item_type list[] = {\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_ETH,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_IPV6_EXT,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_END,\n+\t\t\t};\n+\t\t\tint ret;\n+\n+\t\t\tret = rte_flow_expand_rss_is_supported(supported, list);\n+\t\t\tif (ret) {\n+\t\t\t\toff += rte_flow_expand_rss_item\n+\t\t\t\t\t(addr, (off <= size) ? size - off : 0,\n+\t\t\t\t\t pat, new);\n+\t\t\t\tif (off <= size) {\n+\t\t\t\t\trte_flow_expand_rss_update(buf, addr,\n+\t\t\t\t\t\t\t\t   priority);\n+\t\t\t\t\taddr = (void *)((uintptr_t)buf + off);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\tif (types & (ETH_RSS_TCP | ETH_RSS_UDP)) {\n+\t\t++priority;\n+\t\tif ((types & ETH_RSS_NONFRAG_IPV4_UDP) &&\n+\t\t    !(layer.ipv6 || layer.ipv6_ex || layer.tcp || layer.udp)) {\n+\t\t\tconst struct rte_flow_item new[] = {\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_IPV4 },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_UDP },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_END },\n+\t\t\t};\n+\t\t\tconst enum rte_flow_item_type list[] = {\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_ETH,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_UDP,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_END,\n+\t\t\t};\n+\t\t\tint ret;\n+\n+\t\t\tret = rte_flow_expand_rss_is_supported(supported, list);\n+\t\t\tif (ret) {\n+\t\t\t\toff += rte_flow_expand_rss_item\n+\t\t\t\t\t(addr, (off <= size) ? size - off : 0,\n+\t\t\t\t\t pat, layer.ipv4 ? &new[1] : new);\n+\t\t\t\tif (off <= size) {\n+\t\t\t\t\trte_flow_expand_rss_update(buf, addr,\n+\t\t\t\t\t\t\t\t   priority);\n+\t\t\t\t\taddr = (void *)((uintptr_t)buf + off);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif ((types & ETH_RSS_NONFRAG_IPV4_TCP) &&\n+\t\t    !(layer.ipv6 || layer.ipv6_ex || layer.tcp || layer.udp)) {\n+\t\t\tconst struct rte_flow_item new[] = {\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_IPV4 },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_TCP },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_END },\n+\t\t\t};\n+\t\t\tconst enum rte_flow_item_type list[] = {\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_ETH,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_TCP,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_END,\n+\t\t\t};\n+\t\t\tint ret;\n+\n+\t\t\tret = rte_flow_expand_rss_is_supported(supported, list);\n+\t\t\tif (ret) {\n+\t\t\t\toff += rte_flow_expand_rss_item\n+\t\t\t\t\t(addr, (off <= size) ? size - off : 0,\n+\t\t\t\t\t pat, layer.ipv4 ? &new[1] : new);\n+\t\t\t\tif (off <= size) {\n+\t\t\t\t\trte_flow_expand_rss_update(buf, addr,\n+\t\t\t\t\t\t\t\t   priority);\n+\t\t\t\t\taddr = (void *)((uintptr_t)buf + off);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif ((types & ETH_RSS_NONFRAG_IPV6_UDP) &&\n+\t\t    !(layer.ipv4 || layer.tcp || layer.udp)) {\n+\t\t\tconst struct rte_flow_item new[] = {\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_IPV6 },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_UDP },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_END },\n+\t\t\t};\n+\t\t\tconst enum rte_flow_item_type list[] = {\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_ETH,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_UDP,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_END,\n+\t\t\t};\n+\t\t\tint ret;\n+\n+\t\t\tret = rte_flow_expand_rss_is_supported(supported, list);\n+\t\t\tif (ret) {\n+\t\t\t\toff += rte_flow_expand_rss_item\n+\t\t\t\t\t(addr, (off <= size) ? size - off : 0,\n+\t\t\t\t\t pat, layer.ipv6 ? &new[1] : new);\n+\t\t\t\tif (off <= size) {\n+\t\t\t\t\trte_flow_expand_rss_update(buf, addr,\n+\t\t\t\t\t\t\t\t   priority);\n+\t\t\t\t\taddr = (void *)((uintptr_t)buf + off);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif ((types & (ETH_RSS_NONFRAG_IPV6_TCP |\n+\t\t\t      ETH_RSS_IPV6_TCP_EX)) &&\n+\t\t    !(layer.ipv4 || layer.tcp || layer.udp)) {\n+\t\t\tconst struct rte_flow_item new[] = {\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_IPV6 },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_TCP },\n+\t\t\t\t{ .type = RTE_FLOW_ITEM_TYPE_END },\n+\t\t\t};\n+\t\t\tconst enum rte_flow_item_type list[] = {\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_ETH,\n+\t\t\t\t(layer.ipv6_ex ?\n+\t\t\t\t RTE_FLOW_ITEM_TYPE_IPV6_EXT :\n+\t\t\t\t RTE_FLOW_ITEM_TYPE_IPV6),\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_UDP,\n+\t\t\t\tRTE_FLOW_ITEM_TYPE_END,\n+\t\t\t};\n+\t\t\tint ret;\n+\n+\t\t\tret = rte_flow_expand_rss_is_supported(supported, list);\n+\t\t\tif (ret) {\n+\t\t\t\toff += rte_flow_expand_rss_item\n+\t\t\t\t\t(addr, (off <= size) ? size - off : 0,\n+\t\t\t\t\t pat, layer.ipv6 ? &new[1] : new);\n+\t\t\t\tif (off <= size) {\n+\t\t\t\t\trte_flow_expand_rss_update(buf, addr,\n+\t\t\t\t\t\t\t\t   priority);\n+\t\t\t\t\taddr = (void *)((uintptr_t)buf + off);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn off;\n+}\ndiff --git a/lib/librte_ethdev/rte_flow_driver.h b/lib/librte_ethdev/rte_flow_driver.h\nindex 1c90c600d..9058a8715 100644\n--- a/lib/librte_ethdev/rte_flow_driver.h\n+++ b/lib/librte_ethdev/rte_flow_driver.h\n@@ -114,6 +114,38 @@ struct rte_flow_ops {\n const struct rte_flow_ops *\n rte_flow_ops_get(uint16_t port_id, struct rte_flow_error *error);\n \n+/**\n+ * Expansion structure for RSS flows.\n+ */\n+struct rte_flow_expand_rss {\n+\tuint32_t entries; /**< Number of entries in the following arrays. */\n+\tstruct rte_flow_item **patterns; /**< Expanded pattern array. */\n+\tuint32_t *priority; /**< Priority offset for each expansion. */\n+};\n+\n+/**\n+ * Expand RSS flows into several possible flows according to the RSS hash\n+ * fields requested and the driver capabilities.\n+ *\n+ * @param[in,out] buf\n+ *   Buffer to store the result expansion.\n+ * @param[in] size\n+ *   Size in octets of the buffer.\n+ * @param[in] pat\n+ *   User flow pattern.\n+ * @param[in] types\n+ *   RSS types expected (see ETH_RSS_*).\n+ * @param[in] supported.\n+ *   List of support expansion pattern from the device.\n+ *\n+ * @return\n+ *   The size in octets used to expand.\n+ */\n+int\n+rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size,\n+\t\t    const struct rte_flow_item *pat, uint64_t types,\n+\t\t    const enum rte_flow_item_type **supported);\n+\n #ifdef __cplusplus\n }\n #endif\n",
    "prefixes": [
        "v3"
    ]
}