get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 52476,
    "url": "http://patches.dpdk.org/api/patches/52476/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1554813689-26834-7-git-send-email-rosen.xu@intel.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": "<1554813689-26834-7-git-send-email-rosen.xu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1554813689-26834-7-git-send-email-rosen.xu@intel.com",
    "date": "2019-04-09T12:41:21",
    "name": "[v6,06/14] net/ipn3ke: add IPN3KE Flow of PMD driver",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "8959ea334806609fefcb7497f7919f69f7d643fc",
    "submitter": {
        "id": 946,
        "url": "http://patches.dpdk.org/api/people/946/?format=api",
        "name": "Xu, Rosen",
        "email": "rosen.xu@intel.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/1554813689-26834-7-git-send-email-rosen.xu@intel.com/mbox/",
    "series": [
        {
            "id": 4203,
            "url": "http://patches.dpdk.org/api/series/4203/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=4203",
            "date": "2019-04-09T12:41:15",
            "name": "Add patch set for IPN3KE",
            "version": 6,
            "mbox": "http://patches.dpdk.org/series/4203/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/52476/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/52476/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 046295B36;\n\tTue,  9 Apr 2019 14:40:54 +0200 (CEST)",
            "from mga04.intel.com (mga04.intel.com [192.55.52.120])\n\tby dpdk.org (Postfix) with ESMTP id B7A835B16\n\tfor <dev@dpdk.org>; Tue,  9 Apr 2019 14:40:51 +0200 (CEST)",
            "from orsmga003.jf.intel.com ([10.7.209.27])\n\tby fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t09 Apr 2019 05:40:51 -0700",
            "from dpdkx8602.sh.intel.com ([10.67.110.200])\n\tby orsmga003.jf.intel.com with ESMTP; 09 Apr 2019 05:40:48 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.60,329,1549958400\"; d=\"scan'208\";a=\"141243847\"",
        "From": "Rosen Xu <rosen.xu@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com,\n\trosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com,\n\thaiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, \n\tdavid.lomartire@intel.com, jia.hu@intel.com",
        "Date": "Tue,  9 Apr 2019 20:41:21 +0800",
        "Message-Id": "<1554813689-26834-7-git-send-email-rosen.xu@intel.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1554813689-26834-1-git-send-email-rosen.xu@intel.com>",
        "References": "<1551338000-120348-1-git-send-email-rosen.xu@intel.com>\n\t<1554813689-26834-1-git-send-email-rosen.xu@intel.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=y",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v6 06/14] net/ipn3ke: add IPN3KE Flow of PMD\n\tdriver",
        "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": "Add Intel FPGA Acceleration NIC IPN3KE Flow of PMD driver.\n\nSigned-off-by: Rosen Xu <rosen.xu@intel.com>\nSigned-off-by: Andy Pei <andy.pei@intel.com>\nSigned-off-by: Dan Wei <dan.wei@intel.com>\n---\n drivers/net/ipn3ke/Makefile             |    1 +\n drivers/net/ipn3ke/ipn3ke_ethdev.c      |    5 +\n drivers/net/ipn3ke/ipn3ke_ethdev.h      |    1 +\n drivers/net/ipn3ke/ipn3ke_flow.c        | 1374 +++++++++++++++++++++++++++++++\n drivers/net/ipn3ke/ipn3ke_flow.h        |  106 +++\n drivers/net/ipn3ke/ipn3ke_representor.c |    3 +-\n drivers/net/ipn3ke/ipn3ke_tm.c          |    1 +\n drivers/net/ipn3ke/meson.build          |    3 +-\n 8 files changed, 1492 insertions(+), 2 deletions(-)\n create mode 100644 drivers/net/ipn3ke/ipn3ke_flow.c\n create mode 100644 drivers/net/ipn3ke/ipn3ke_flow.h",
    "diff": "diff --git a/drivers/net/ipn3ke/Makefile b/drivers/net/ipn3ke/Makefile\nindex 38d9384..8c3ae37 100644\n--- a/drivers/net/ipn3ke/Makefile\n+++ b/drivers/net/ipn3ke/Makefile\n@@ -35,5 +35,6 @@ LIBABIVER := 1\n SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_ethdev.c\n SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_representor.c\n SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_tm.c\n+SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_flow.c\n \n include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.c b/drivers/net/ipn3ke/ipn3ke_ethdev.c\nindex 29828f3..16893c7 100644\n--- a/drivers/net/ipn3ke/ipn3ke_ethdev.c\n+++ b/drivers/net/ipn3ke/ipn3ke_ethdev.c\n@@ -21,6 +21,7 @@\n #include <ifpga_logs.h>\n \n #include \"ipn3ke_rawdev_api.h\"\n+#include \"ipn3ke_flow.h\"\n #include \"ipn3ke_logs.h\"\n #include \"ipn3ke_ethdev.h\"\n \n@@ -278,6 +279,10 @@\n \t\tif (ret)\n \t\t\treturn ret;\n \t\thw->tm_hw_enable = 1;\n+\n+\t\tret = ipn3ke_flow_init(hw);\n+\t\tif (ret)\n+\t\t\treturn ret;\n \t\thw->flow_hw_enable = 1;\n \t}\n \ndiff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.h b/drivers/net/ipn3ke/ipn3ke_ethdev.h\nindex 6985a25..948a57e 100644\n--- a/drivers/net/ipn3ke/ipn3ke_ethdev.h\n+++ b/drivers/net/ipn3ke/ipn3ke_ethdev.h\n@@ -291,6 +291,7 @@ struct ipn3ke_hw {\n \tuint32_t acc_tm;\n \tuint32_t acc_flow;\n \n+\tstruct ipn3ke_flow_list flow_list;\n \tuint32_t flow_max_entries;\n \tuint32_t flow_num_entries;\n \ndiff --git a/drivers/net/ipn3ke/ipn3ke_flow.c b/drivers/net/ipn3ke/ipn3ke_flow.c\nnew file mode 100644\nindex 0000000..e5937df\n--- /dev/null\n+++ b/drivers/net/ipn3ke/ipn3ke_flow.c\n@@ -0,0 +1,1374 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2019 Intel Corporation\n+ */\n+\n+#include <sys/queue.h>\n+#include <stdio.h>\n+#include <errno.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include <unistd.h>\n+#include <stdarg.h>\n+\n+#include <rte_io.h>\n+#include <rte_debug.h>\n+#include <rte_ether.h>\n+#include <rte_ethdev_driver.h>\n+#include <rte_log.h>\n+#include <rte_malloc.h>\n+#include <rte_eth_ctrl.h>\n+#include <rte_tailq.h>\n+\n+#include \"ipn3ke_rawdev_api.h\"\n+#include \"ipn3ke_flow.h\"\n+#include \"ipn3ke_logs.h\"\n+#include \"ipn3ke_ethdev.h\"\n+\n+/** Static initializer for items. */\n+#define FLOW_PATTERNS(...) \\\n+\t((const enum rte_flow_item_type []) { \\\n+\t\t__VA_ARGS__, RTE_FLOW_ITEM_TYPE_END, \\\n+\t})\n+\n+enum IPN3KE_HASH_KEY_TYPE {\n+\tIPN3KE_HASH_KEY_VXLAN,\n+\tIPN3KE_HASH_KEY_MAC,\n+\tIPN3KE_HASH_KEY_QINQ,\n+\tIPN3KE_HASH_KEY_MPLS,\n+\tIPN3KE_HASH_KEY_IP_TCP,\n+\tIPN3KE_HASH_KEY_IP_UDP,\n+\tIPN3KE_HASH_KEY_IP_NVGRE,\n+\tIPN3KE_HASH_KEY_VXLAN_IP_UDP,\n+};\n+\n+struct ipn3ke_flow_parse {\n+\tuint32_t mark:1; /**< Set if the flow is marked. */\n+\tuint32_t drop:1; /**< ACL drop. */\n+\tuint32_t key_type:IPN3KE_FLOW_KEY_ID_BITS;\n+\tuint32_t mark_id:IPN3KE_FLOW_RESULT_UID_BITS; /**< Mark identifier. */\n+\tuint8_t key_len; /**< Length in bit. */\n+\tuint8_t key[BITS_TO_BYTES(IPN3KE_FLOW_KEY_DATA_BITS)];\n+\t\t/**< key1, key2 */\n+};\n+\n+typedef int (*pattern_filter_t)(const struct rte_flow_item patterns[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser);\n+\n+\n+struct ipn3ke_flow_pattern {\n+\tconst enum rte_flow_item_type *const items;\n+\n+\tpattern_filter_t filter;\n+};\n+\n+/*\n+ * @ RTL definition:\n+ * typedef struct packed {\n+ * logic [47:0]    vxlan_inner_mac;\n+ * logic [23:0]    vxlan_vni;\n+ * } Hash_Key_Vxlan_t;\n+ *\n+ * @ flow items:\n+ * RTE_FLOW_ITEM_TYPE_VXLAN\n+ * RTE_FLOW_ITEM_TYPE_ETH\n+ */\n+static int\n+ipn3ke_pattern_vxlan(const struct rte_flow_item patterns[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tconst struct rte_flow_item_vxlan *vxlan = NULL;\n+\tconst struct rte_flow_item_eth *eth = NULL;\n+\tconst struct rte_flow_item *item;\n+\n+\tfor (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (/*!item->spec || item->mask || */item->last) {\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Only support item with 'spec'\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\teth = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[0],\n+\t\t\t\t\teth->src.addr_bytes,\n+\t\t\t\t\tETHER_ADDR_LEN);\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\t\tvxlan = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[6], vxlan->vni, 3);\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Not support item type\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t}\n+\n+\tif (vxlan != NULL && eth != NULL) {\n+\t\tparser->key_len = 48 + 24;\n+\t\treturn 0;\n+\t}\n+\n+\trte_flow_error_set(error,\n+\t\t\tEINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\tpatterns,\n+\t\t\t\"Missed some patterns\");\n+\treturn -rte_errno;\n+}\n+\n+/*\n+ * @ RTL definition:\n+ * typedef struct packed {\n+ * logic [47:0]    eth_smac;\n+ * } Hash_Key_Mac_t;\n+ *\n+ * @ flow items:\n+ * RTE_FLOW_ITEM_TYPE_ETH\n+ */\n+static int\n+ipn3ke_pattern_mac(const struct rte_flow_item patterns[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tconst struct rte_flow_item_eth *eth = NULL;\n+\tconst struct rte_flow_item *item;\n+\n+\tfor (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (!item->spec || item->mask || item->last) {\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Only support item with 'spec'\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\teth = item->spec;\n+\n+\t\t\trte_memcpy(parser->key,\n+\t\t\t\t\teth->src.addr_bytes,\n+\t\t\t\t\tETHER_ADDR_LEN);\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Not support item type\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t}\n+\n+\tif (eth != NULL) {\n+\t\tparser->key_len = 48;\n+\t\treturn 0;\n+\t}\n+\n+\trte_flow_error_set(error,\n+\t\t\tEINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\tpatterns,\n+\t\t\t\"Missed some patterns\");\n+\treturn -rte_errno;\n+}\n+\n+/*\n+ * @ RTL definition:\n+ * typedef struct packed {\n+ * logic [11:0]    outer_vlan_id;\n+ * logic [11:0]    inner_vlan_id;\n+ * } Hash_Key_QinQ_t;\n+ *\n+ * @ flow items:\n+ * RTE_FLOW_ITEM_TYPE_VLAN\n+ * RTE_FLOW_ITEM_TYPE_VLAN\n+ */\n+static int\n+ipn3ke_pattern_qinq(const struct rte_flow_item patterns[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tconst struct rte_flow_item_vlan *outer_vlan = NULL;\n+\tconst struct rte_flow_item_vlan *inner_vlan = NULL;\n+\tconst struct rte_flow_item *item;\n+\tuint16_t tci;\n+\n+\tfor (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (!item->spec || item->mask || item->last) {\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Only support item with 'spec'\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n+\t\t\tif (!outer_vlan) {\n+\t\t\t\touter_vlan = item->spec;\n+\n+\t\t\t\ttci = rte_be_to_cpu_16(outer_vlan->tci);\n+\t\t\t\tparser->key[0]  = (tci & 0xff0) >> 4;\n+\t\t\t\tparser->key[1] |= (tci & 0x00f) << 4;\n+\t\t\t} else {\n+\t\t\t\tinner_vlan = item->spec;\n+\n+\t\t\t\ttci = rte_be_to_cpu_16(inner_vlan->tci);\n+\t\t\t\tparser->key[1] |= (tci & 0xf00) >> 8;\n+\t\t\t\tparser->key[2]  = (tci & 0x0ff);\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Not support item type\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t}\n+\n+\tif (outer_vlan != NULL && inner_vlan != NULL) {\n+\t\tparser->key_len = 12 + 12;\n+\t\treturn 0;\n+\t}\n+\n+\trte_flow_error_set(error,\n+\t\t\tEINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\tpatterns,\n+\t\t\t\"Missed some patterns\");\n+\treturn -rte_errno;\n+}\n+\n+/*\n+ * @ RTL definition:\n+ * typedef struct packed {\n+ * logic [19:0]    mpls_label1;\n+ * logic [19:0]    mpls_label2;\n+ * } Hash_Key_Mpls_t;\n+ *\n+ * @ flow items:\n+ * RTE_FLOW_ITEM_TYPE_MPLS\n+ * RTE_FLOW_ITEM_TYPE_MPLS\n+ */\n+static int\n+ipn3ke_pattern_mpls(const struct rte_flow_item patterns[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tconst struct rte_flow_item_mpls *mpls1 = NULL;\n+\tconst struct rte_flow_item_mpls *mpls2 = NULL;\n+\tconst struct rte_flow_item *item;\n+\n+\tfor (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (!item->spec || item->mask || item->last) {\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Only support item with 'spec'\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_MPLS:\n+\t\t\tif (!mpls1) {\n+\t\t\t\tmpls1 = item->spec;\n+\n+\t\t\t\tparser->key[0] = mpls1->label_tc_s[0];\n+\t\t\t\tparser->key[1] = mpls1->label_tc_s[1];\n+\t\t\t\tparser->key[2] = mpls1->label_tc_s[2] & 0xf0;\n+\t\t\t} else {\n+\t\t\t\tmpls2 = item->spec;\n+\n+\t\t\t\tparser->key[2] |=\n+\t\t\t\t\t((mpls2->label_tc_s[0] & 0xf0) >> 4);\n+\t\t\t\tparser->key[3] =\n+\t\t\t\t\t((mpls2->label_tc_s[0] & 0xf) << 4) |\n+\t\t\t\t\t((mpls2->label_tc_s[1] & 0xf0) >> 4);\n+\t\t\t\tparser->key[4] =\n+\t\t\t\t\t((mpls2->label_tc_s[1] & 0xf) << 4) |\n+\t\t\t\t\t((mpls2->label_tc_s[2] & 0xf0) >> 4);\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Not support item type\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t}\n+\n+\tif (mpls1 != NULL && mpls2 != NULL) {\n+\t\tparser->key_len = 20 + 20;\n+\t\treturn 0;\n+\t}\n+\n+\trte_flow_error_set(error,\n+\t\t\tEINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\tpatterns,\n+\t\t\t\"Missed some patterns\");\n+\treturn -rte_errno;\n+}\n+\n+/*\n+ * @ RTL definition:\n+ * typedef struct packed {\n+ * logic [31:0]    ip_sa;\n+ * logic [15:0]    tcp_sport;\n+ * } Hash_Key_Ip_Tcp_t;\n+ *\n+ * @ flow items:\n+ * RTE_FLOW_ITEM_TYPE_IPV4\n+ * RTE_FLOW_ITEM_TYPE_TCP\n+ */\n+static int\n+ipn3ke_pattern_ip_tcp(const struct rte_flow_item patterns[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tconst struct rte_flow_item_ipv4 *ipv4 = NULL;\n+\tconst struct rte_flow_item_tcp *tcp = NULL;\n+\tconst struct rte_flow_item *item;\n+\n+\tfor (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (!item->spec || item->mask || item->last) {\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Only support item with 'spec'\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tipv4 = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[0], &ipv4->hdr.src_addr, 4);\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\t\ttcp = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[4], &tcp->hdr.src_port, 2);\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Not support item type\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t}\n+\n+\tif (ipv4 != NULL && tcp != NULL) {\n+\t\tparser->key_len = 32 + 16;\n+\t\treturn 0;\n+\t}\n+\n+\trte_flow_error_set(error,\n+\t\t\tEINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\tpatterns,\n+\t\t\t\"Missed some patterns\");\n+\treturn -rte_errno;\n+}\n+\n+/*\n+ * @ RTL definition:\n+ * typedef struct packed {\n+ * logic [31:0]    ip_sa;\n+ * logic [15:0]    udp_sport;\n+ * } Hash_Key_Ip_Udp_t;\n+ *\n+ * @ flow items:\n+ * RTE_FLOW_ITEM_TYPE_IPV4\n+ * RTE_FLOW_ITEM_TYPE_UDP\n+ */\n+static int\n+ipn3ke_pattern_ip_udp(const struct rte_flow_item patterns[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tconst struct rte_flow_item_ipv4 *ipv4 = NULL;\n+\tconst struct rte_flow_item_udp *udp = NULL;\n+\tconst struct rte_flow_item *item;\n+\n+\tfor (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (!item->spec || item->mask || item->last) {\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Only support item with 'spec'\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tipv4 = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[0], &ipv4->hdr.src_addr, 4);\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tudp = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[4], &udp->hdr.src_port, 2);\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Not support item type\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t}\n+\n+\tif (ipv4 != NULL && udp != NULL) {\n+\t\tparser->key_len = 32 + 16;\n+\t\treturn 0;\n+\t}\n+\n+\trte_flow_error_set(error,\n+\t\t\tEINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\tpatterns,\n+\t\t\t\"Missed some patterns\");\n+\treturn -rte_errno;\n+}\n+\n+/*\n+ * @ RTL definition:\n+ * typedef struct packed {\n+ * logic [31:0]    ip_sa;\n+ * logic [15:0]    udp_sport;\n+ * logic [23:0]    vsid;\n+ * } Hash_Key_Ip_Nvgre_t;\n+ *\n+ * @ flow items:\n+ * RTE_FLOW_ITEM_TYPE_IPV4\n+ * RTE_FLOW_ITEM_TYPE_UDP\n+ * RTE_FLOW_ITEM_TYPE_NVGRE\n+ */\n+static int\n+ipn3ke_pattern_ip_nvgre(const struct rte_flow_item patterns[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tconst struct rte_flow_item_nvgre *nvgre = NULL;\n+\tconst struct rte_flow_item_ipv4 *ipv4 = NULL;\n+\tconst struct rte_flow_item_udp *udp = NULL;\n+\tconst struct rte_flow_item *item;\n+\n+\tfor (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (!item->spec || item->mask || item->last) {\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Only support item with 'spec'\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tipv4 = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[0], &ipv4->hdr.src_addr, 4);\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tudp = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[4], &udp->hdr.src_port, 2);\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ITEM_TYPE_NVGRE:\n+\t\t\tnvgre = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[6], nvgre->tni, 3);\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Not support item type\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t}\n+\n+\tif (ipv4 != NULL && udp != NULL && nvgre != NULL) {\n+\t\tparser->key_len = 32 + 16 + 24;\n+\t\treturn 0;\n+\t}\n+\n+\trte_flow_error_set(error,\n+\t\t\tEINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\tpatterns,\n+\t\t\t\"Missed some patterns\");\n+\treturn -rte_errno;\n+}\n+\n+/*\n+ * @ RTL definition:\n+ * typedef struct packed{\n+ * logic [23:0]    vxlan_vni;\n+ * logic [31:0]    ip_sa;\n+ * logic [15:0]    udp_sport;\n+ * } Hash_Key_Vxlan_Ip_Udp_t;\n+ *\n+ * @ flow items:\n+ * RTE_FLOW_ITEM_TYPE_VXLAN\n+ * RTE_FLOW_ITEM_TYPE_IPV4\n+ * RTE_FLOW_ITEM_TYPE_UDP\n+ */\n+static int\n+ipn3ke_pattern_vxlan_ip_udp(const struct rte_flow_item patterns[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tconst struct rte_flow_item_vxlan *vxlan = NULL;\n+\tconst struct rte_flow_item_ipv4 *ipv4 = NULL;\n+\tconst struct rte_flow_item_udp *udp = NULL;\n+\tconst struct rte_flow_item *item;\n+\n+\tfor (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (!item->spec || item->mask || item->last) {\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Only support item with 'spec'\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\t\tvxlan = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[0], vxlan->vni, 3);\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tipv4 = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[3], &ipv4->hdr.src_addr, 4);\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tudp = item->spec;\n+\n+\t\t\trte_memcpy(&parser->key[7], &udp->hdr.src_port, 2);\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tEINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem,\n+\t\t\t\t\t\"Not support item type\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t}\n+\n+\tif (vxlan != NULL && ipv4 != NULL && udp != NULL) {\n+\t\tparser->key_len = 24 + 32 + 16;\n+\t\treturn 0;\n+\t}\n+\n+\trte_flow_error_set(error,\n+\t\t\tEINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\tpatterns,\n+\t\t\t\"Missed some patterns\");\n+\treturn -rte_errno;\n+}\n+\n+static const struct ipn3ke_flow_pattern ipn3ke_supported_patterns[] = {\n+\t[IPN3KE_HASH_KEY_VXLAN] = {\n+\t\t.items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_VXLAN,\n+\t\t\t\t\tRTE_FLOW_ITEM_TYPE_ETH),\n+\t\t.filter = ipn3ke_pattern_vxlan,\n+\t},\n+\n+\t[IPN3KE_HASH_KEY_MAC] = {\n+\t\t.items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_ETH),\n+\t\t.filter = ipn3ke_pattern_mac,\n+\t},\n+\n+\t[IPN3KE_HASH_KEY_QINQ] = {\n+\t\t.items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_VLAN,\n+\t\t\t\t\tRTE_FLOW_ITEM_TYPE_VLAN),\n+\t\t.filter = ipn3ke_pattern_qinq,\n+\t},\n+\n+\t[IPN3KE_HASH_KEY_MPLS] = {\n+\t\t.items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_MPLS,\n+\t\t\t\t\tRTE_FLOW_ITEM_TYPE_MPLS),\n+\t\t.filter = ipn3ke_pattern_mpls,\n+\t},\n+\n+\t[IPN3KE_HASH_KEY_IP_TCP] = {\n+\t\t.items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_IPV4,\n+\t\t\t\t\tRTE_FLOW_ITEM_TYPE_TCP),\n+\t\t.filter = ipn3ke_pattern_ip_tcp,\n+\t},\n+\n+\t[IPN3KE_HASH_KEY_IP_UDP] = {\n+\t\t.items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_IPV4,\n+\t\t\t\t\tRTE_FLOW_ITEM_TYPE_UDP),\n+\t\t.filter = ipn3ke_pattern_ip_udp,\n+\t},\n+\n+\t[IPN3KE_HASH_KEY_IP_NVGRE] = {\n+\t\t.items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_IPV4,\n+\t\t\t\t\tRTE_FLOW_ITEM_TYPE_UDP,\n+\t\t\t\t\tRTE_FLOW_ITEM_TYPE_NVGRE),\n+\t\t.filter = ipn3ke_pattern_ip_nvgre,\n+\t},\n+\n+\t[IPN3KE_HASH_KEY_VXLAN_IP_UDP] = {\n+\t\t.items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_VXLAN,\n+\t\t\t\t\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\t\t\t\t\tRTE_FLOW_ITEM_TYPE_UDP),\n+\t\t.filter = ipn3ke_pattern_vxlan_ip_udp,\n+\t},\n+};\n+\n+static int\n+ipn3ke_flow_convert_attributes(const struct rte_flow_attr *attr,\n+\t\t\t\tstruct rte_flow_error *error)\n+{\n+\tif (!attr) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tEINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR,\n+\t\t\t\tNULL,\n+\t\t\t\t\"NULL attribute.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (attr->group) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tENOTSUP,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_GROUP,\n+\t\t\t\tNULL,\n+\t\t\t\t\"groups are not supported\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (attr->egress) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tENOTSUP,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_EGRESS,\n+\t\t\t\tNULL,\n+\t\t\t\t\"egress is not supported\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (attr->transfer) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tENOTSUP,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,\n+\t\t\t\tNULL,\n+\t\t\t\t\"transfer is not supported\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (!attr->ingress) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tENOTSUP,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_INGRESS,\n+\t\t\t\tNULL,\n+\t\t\t\t\"only ingress is supported\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+ipn3ke_flow_convert_actions(const struct rte_flow_action actions[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tconst struct rte_flow_action_mark *mark = NULL;\n+\n+\tif (!actions) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tEINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_NUM,\n+\t\t\t\tNULL,\n+\t\t\t\t\"NULL action.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {\n+\t\tswitch (actions->type) {\n+\t\tcase RTE_FLOW_ACTION_TYPE_VOID:\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ACTION_TYPE_MARK:\n+\t\t\tif (mark) {\n+\t\t\t\trte_flow_error_set(error,\n+\t\t\t\t\t\tENOTSUP,\n+\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\tactions,\n+\t\t\t\t\t\t\"duplicated mark\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tmark = actions->conf;\n+\t\t\tif (!mark) {\n+\t\t\t\trte_flow_error_set(error,\n+\t\t\t\t\t\tEINVAL,\n+\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\tactions,\n+\t\t\t\t\t\t\"mark must be defined\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t} else if (mark->id > IPN3KE_FLOW_RESULT_UID_MAX) {\n+\t\t\t\trte_flow_error_set(error,\n+\t\t\t\t\t\tENOTSUP,\n+\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\tactions,\n+\t\t\t\t\t\t\"mark id is out of range\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tparser->mark = 1;\n+\t\t\tparser->mark_id = mark->id;\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n+\t\t\tparser->drop = 1;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trte_flow_error_set(error,\n+\t\t\t\t\tENOTSUP,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\tactions,\n+\t\t\t\t\t\"invalid action\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t}\n+\n+\tif (!parser->drop && !parser->mark) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tEINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\tactions,\n+\t\t\t\t\"no valid actions\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static bool\n+ipn3ke_match_pattern(const enum rte_flow_item_type *patterns,\n+\t\t\t\tconst struct rte_flow_item *input)\n+{\n+\tconst struct rte_flow_item *item = input;\n+\n+\twhile ((*patterns == item->type) &&\n+\t\t(*patterns != RTE_FLOW_ITEM_TYPE_END)) {\n+\t\tpatterns++;\n+\t\titem++;\n+\t}\n+\n+\treturn (*patterns == RTE_FLOW_ITEM_TYPE_END &&\n+\t\titem->type == RTE_FLOW_ITEM_TYPE_END);\n+}\n+\n+static pattern_filter_t\n+ipn3ke_find_filter_func(const struct rte_flow_item *input,\n+\t\t\t\tuint32_t *idx)\n+{\n+\tpattern_filter_t filter = NULL;\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < RTE_DIM(ipn3ke_supported_patterns); i++) {\n+\t\tif (ipn3ke_match_pattern(ipn3ke_supported_patterns[i].items,\n+\t\t\t\t\tinput)) {\n+\t\t\tfilter = ipn3ke_supported_patterns[i].filter;\n+\t\t\t*idx = i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn filter;\n+}\n+\n+static int\n+ipn3ke_flow_convert_items(const struct rte_flow_item items[],\n+\tstruct rte_flow_error *error, struct ipn3ke_flow_parse *parser)\n+{\n+\tpattern_filter_t filter = NULL;\n+\tuint32_t idx;\n+\n+\tif (!items) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tEINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_NUM,\n+\t\t\t\tNULL,\n+\t\t\t\t\"NULL pattern.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tfilter = ipn3ke_find_filter_func(items, &idx);\n+\n+\tif (!filter) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tEINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\titems,\n+\t\t\t\t\"Unsupported pattern\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tparser->key_type = idx;\n+\n+\treturn filter(items, error, parser);\n+}\n+\n+/* Put the least @nbits of @data into @offset of @dst bits stream, and\n+ * the @offset starts from MSB to LSB in each byte.\n+ *\n+ * MSB    LSB\n+ *  +------+------+------+------+\n+ *  |      |      |      |      |\n+ *  +------+------+------+------+\n+ *       ^                 ^\n+ *       |<- data: nbits ->|\n+ *       |\n+ *     offset\n+ */\n+static void\n+copy_data_bits(uint8_t *dst, uint64_t data,\n+\t\tuint32_t offset, uint8_t nbits)\n+{\n+\tuint8_t set, *p = &dst[offset / BITS_PER_BYTE];\n+\tuint8_t bits_to_set = BITS_PER_BYTE - (offset % BITS_PER_BYTE);\n+\tuint8_t mask_to_set = 0xff >> (offset % BITS_PER_BYTE);\n+\tuint32_t size = offset + nbits;\n+\n+\tif (nbits > (sizeof(data) * BITS_PER_BYTE)) {\n+\t\tIPN3KE_AFU_PMD_ERR(\"nbits is out of range\");\n+\t\treturn;\n+\t}\n+\n+\twhile (nbits - bits_to_set >= 0) {\n+\t\tset = data >> (nbits - bits_to_set);\n+\n+\t\t*p &= ~mask_to_set;\n+\t\t*p |= (set & mask_to_set);\n+\n+\t\tnbits -= bits_to_set;\n+\t\tbits_to_set = BITS_PER_BYTE;\n+\t\tmask_to_set = 0xff;\n+\t\tp++;\n+\t}\n+\n+\tif (nbits) {\n+\t\tuint8_t shift = BITS_PER_BYTE - (size % BITS_PER_BYTE);\n+\n+\t\tset = data << shift;\n+\t\tmask_to_set = 0xff << shift;\n+\n+\t\t*p &= ~mask_to_set;\n+\t\t*p |= (set & mask_to_set);\n+\t}\n+}\n+\n+static void\n+ipn3ke_flow_key_generation(struct ipn3ke_flow_parse *parser,\n+\t\t\t\tstruct rte_flow *flow)\n+{\n+\tuint32_t i, shift_bytes, len_in_bytes, offset;\n+\tuint64_t key;\n+\tuint8_t *dst;\n+\n+\tdst = flow->rule.key;\n+\n+\tcopy_data_bits(dst,\n+\t\t\tparser->key_type,\n+\t\t\tIPN3KE_FLOW_KEY_ID_OFFSET,\n+\t\t\tIPN3KE_FLOW_KEY_ID_BITS);\n+\n+\t/* The MSb of key is filled to 0 when it is less than\n+\t * IPN3KE_FLOW_KEY_DATA_BITS bit. And the parsed key data is\n+\t * save as MSB byte first in the array, it needs to move\n+\t * the bits before formatting them.\n+\t */\n+\tkey = 0;\n+\tshift_bytes = 0;\n+\tlen_in_bytes = BITS_TO_BYTES(parser->key_len);\n+\toffset = (IPN3KE_FLOW_KEY_DATA_OFFSET +\n+\t\tIPN3KE_FLOW_KEY_DATA_BITS -\n+\t\tparser->key_len);\n+\n+\tfor (i = 0; i < len_in_bytes; i++) {\n+\t\tkey = (key << 8) | parser->key[i];\n+\n+\t\tif (++shift_bytes == sizeof(key)) {\n+\t\t\tshift_bytes = 0;\n+\n+\t\t\tcopy_data_bits(dst, key, offset,\n+\t\t\t\t\tsizeof(key) * BITS_PER_BYTE);\n+\t\t\toffset += sizeof(key) * BITS_PER_BYTE;\n+\t\t\tkey = 0;\n+\t\t}\n+\t}\n+\n+\tif (shift_bytes != 0) {\n+\t\tuint32_t rem_bits;\n+\n+\t\trem_bits = parser->key_len % (sizeof(key) * BITS_PER_BYTE);\n+\t\tkey >>= (shift_bytes * 8 - rem_bits);\n+\t\tcopy_data_bits(dst, key, offset, rem_bits);\n+\t}\n+}\n+\n+static void\n+ipn3ke_flow_result_generation(struct ipn3ke_flow_parse *parser,\n+\t\t\t\tstruct rte_flow *flow)\n+{\n+\tuint8_t *dst;\n+\n+\tif (parser->drop)\n+\t\treturn;\n+\n+\tdst = flow->rule.result;\n+\n+\tcopy_data_bits(dst,\n+\t\t\t1,\n+\t\t\tIPN3KE_FLOW_RESULT_ACL_OFFSET,\n+\t\t\tIPN3KE_FLOW_RESULT_ACL_BITS);\n+\n+\tcopy_data_bits(dst,\n+\t\t\tparser->mark_id,\n+\t\t\tIPN3KE_FLOW_RESULT_UID_OFFSET,\n+\t\t\tIPN3KE_FLOW_RESULT_UID_BITS);\n+}\n+\n+#define MHL_COMMAND_TIME_COUNT        0xFFFF\n+#define MHL_COMMAND_TIME_INTERVAL_US  10\n+\n+static int\n+ipn3ke_flow_hw_update(struct ipn3ke_hw *hw,\n+\t\t\tstruct rte_flow *flow, uint32_t is_add)\n+{\n+\tuint32_t *pdata = NULL;\n+\tuint32_t data;\n+\tuint32_t time_out = MHL_COMMAND_TIME_COUNT;\n+\tuint32_t i;\n+\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE flow dump start\\n\");\n+\n+\tpdata = (uint32_t *)flow->rule.key;\n+\tIPN3KE_AFU_PMD_DEBUG(\" - key   :\");\n+\n+\tfor (i = 0; i < RTE_DIM(flow->rule.key); i++)\n+\t\tIPN3KE_AFU_PMD_DEBUG(\" %02x\", flow->rule.key[i]);\n+\n+\tfor (i = 0; i < 4; i++)\n+\t\tIPN3KE_AFU_PMD_DEBUG(\" %02x\", ipn3ke_swap32(pdata[3 - i]));\n+\tIPN3KE_AFU_PMD_DEBUG(\"\\n\");\n+\n+\tpdata = (uint32_t *)flow->rule.result;\n+\tIPN3KE_AFU_PMD_DEBUG(\" - result:\");\n+\n+\tfor (i = 0; i < RTE_DIM(flow->rule.result); i++)\n+\t\tIPN3KE_AFU_PMD_DEBUG(\" %02x\", flow->rule.result[i]);\n+\n+\tfor (i = 0; i < 1; i++)\n+\t\tIPN3KE_AFU_PMD_DEBUG(\" %02x\", pdata[i]);\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE flow dump end\\n\");\n+\n+\tpdata = (uint32_t *)flow->rule.key;\n+\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_MHL_KEY_0,\n+\t\t\t0,\n+\t\t\tipn3ke_swap32(pdata[3]),\n+\t\t\tIPN3KE_CLF_MHL_KEY_MASK);\n+\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_MHL_KEY_1,\n+\t\t\t0,\n+\t\t\tipn3ke_swap32(pdata[2]),\n+\t\t\tIPN3KE_CLF_MHL_KEY_MASK);\n+\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_MHL_KEY_2,\n+\t\t\t0,\n+\t\t\tipn3ke_swap32(pdata[1]),\n+\t\t\tIPN3KE_CLF_MHL_KEY_MASK);\n+\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_MHL_KEY_3,\n+\t\t\t0,\n+\t\t\tipn3ke_swap32(pdata[0]),\n+\t\t\tIPN3KE_CLF_MHL_KEY_MASK);\n+\n+\tpdata = (uint32_t *)flow->rule.result;\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_MHL_RES,\n+\t\t\t0,\n+\t\t\tipn3ke_swap32(pdata[0]),\n+\t\t\tIPN3KE_CLF_MHL_RES_MASK);\n+\n+\t/* insert/delete the key and result */\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL,\n+\t\t\t\t0,\n+\t\t\t\t0x80000000);\n+\ttime_out = MHL_COMMAND_TIME_COUNT;\n+\twhile (IPN3KE_BIT_ISSET(data, IPN3KE_CLF_MHL_MGMT_CTRL_BIT_BUSY) &&\n+\t\t(time_out > 0)) {\n+\t\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL,\n+\t\t\t\t\t0,\n+\t\t\t\t\t0x80000000);\n+\t\ttime_out--;\n+\t\trte_delay_us(MHL_COMMAND_TIME_INTERVAL_US);\n+\t}\n+\tif (!time_out)\n+\t\treturn -1;\n+\tif (is_add)\n+\t\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL,\n+\t\t\t\t0,\n+\t\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL_INSERT,\n+\t\t\t\t0x3);\n+\telse\n+\t\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL,\n+\t\t\t\t0,\n+\t\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL_DELETE,\n+\t\t\t\t0x3);\n+\n+\treturn 0;\n+}\n+\n+static int\n+ipn3ke_flow_hw_flush(struct ipn3ke_hw *hw)\n+{\n+\tuint32_t data;\n+\tuint32_t time_out = MHL_COMMAND_TIME_COUNT;\n+\n+\t/* flush the MHL lookup table */\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL,\n+\t\t\t\t0,\n+\t\t\t\t0x80000000);\n+\ttime_out = MHL_COMMAND_TIME_COUNT;\n+\twhile (IPN3KE_BIT_ISSET(data, IPN3KE_CLF_MHL_MGMT_CTRL_BIT_BUSY) &&\n+\t\t(time_out > 0)) {\n+\t\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL,\n+\t\t\t\t\t0,\n+\t\t\t\t\t0x80000000);\n+\t\ttime_out--;\n+\t\trte_delay_us(MHL_COMMAND_TIME_INTERVAL_US);\n+\t}\n+\tif (!time_out)\n+\t\treturn -1;\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL,\n+\t\t\t0,\n+\t\t\tIPN3KE_CLF_MHL_MGMT_CTRL_FLUSH,\n+\t\t\t0x3);\n+\n+\treturn 0;\n+}\n+\n+static void\n+ipn3ke_flow_convert_finalise(struct ipn3ke_hw *hw,\n+\tstruct ipn3ke_flow_parse *parser, struct rte_flow *flow)\n+{\n+\tipn3ke_flow_key_generation(parser, flow);\n+\tipn3ke_flow_result_generation(parser, flow);\n+\tipn3ke_flow_hw_update(hw, flow, 1);\n+}\n+\n+static int\n+ipn3ke_flow_convert(const struct rte_flow_attr *attr,\n+\tconst struct rte_flow_item items[],\n+\tconst struct rte_flow_action actions[], struct rte_flow_error *error,\n+\tstruct ipn3ke_flow_parse *parser)\n+{\n+\tint ret;\n+\n+\tret = ipn3ke_flow_convert_attributes(attr, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = ipn3ke_flow_convert_actions(actions, error, parser);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = ipn3ke_flow_convert_items(items, error, parser);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+\n+static int\n+ipn3ke_flow_validate(__rte_unused struct rte_eth_dev *dev,\n+\tconst struct rte_flow_attr *attr, const struct rte_flow_item pattern[],\n+\tconst struct rte_flow_action actions[], struct rte_flow_error *error)\n+{\n+\tstruct ipn3ke_flow_parse parser = {0};\n+\treturn ipn3ke_flow_convert(attr, pattern, actions, error, &parser);\n+}\n+\n+static struct rte_flow *\n+ipn3ke_flow_create(struct rte_eth_dev *dev,\n+\tconst struct rte_flow_attr *attr, const struct rte_flow_item pattern[],\n+\tconst struct rte_flow_action actions[], struct rte_flow_error *error)\n+{\n+\tstruct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);\n+\tstruct ipn3ke_flow_parse parser = {0};\n+\tstruct rte_flow *flow;\n+\tint ret;\n+\n+\tif (hw->flow_num_entries == hw->flow_max_entries) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tENOBUFS,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_HANDLE,\n+\t\t\t\tNULL,\n+\t\t\t\t\"The flow table is full.\");\n+\t\treturn NULL;\n+\t}\n+\n+\tret = ipn3ke_flow_convert(attr, pattern, actions, error, &parser);\n+\tif (ret < 0) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\t-ret,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_HANDLE,\n+\t\t\t\tNULL,\n+\t\t\t\t\"Failed to create flow.\");\n+\t\treturn NULL;\n+\t}\n+\n+\tflow = rte_zmalloc(\"ipn3ke_flow\", sizeof(struct rte_flow), 0);\n+\tif (!flow) {\n+\t\trte_flow_error_set(error,\n+\t\t\t\tENOMEM,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_HANDLE,\n+\t\t\t\tNULL,\n+\t\t\t\t\"Failed to allocate memory\");\n+\t\treturn flow;\n+\t}\n+\n+\tipn3ke_flow_convert_finalise(hw, &parser, flow);\n+\n+\tTAILQ_INSERT_TAIL(&hw->flow_list, flow, next);\n+\n+\treturn flow;\n+}\n+\n+static int\n+ipn3ke_flow_destroy(struct rte_eth_dev *dev,\n+\tstruct rte_flow *flow, struct rte_flow_error *error)\n+{\n+\tstruct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);\n+\tint ret = 0;\n+\n+\tret = ipn3ke_flow_hw_update(hw, flow, 0);\n+\tif (!ret) {\n+\t\tTAILQ_REMOVE(&hw->flow_list, flow, next);\n+\t\trte_free(flow);\n+\t} else {\n+\t\trte_flow_error_set(error,\n+\t\t\t\t-ret,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_HANDLE,\n+\t\t\t\tNULL,\n+\t\t\t\t\"Failed to destroy flow.\");\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int\n+ipn3ke_flow_flush(struct rte_eth_dev *dev,\n+\t\t__rte_unused struct rte_flow_error *error)\n+{\n+\tstruct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);\n+\tstruct rte_flow *flow, *temp;\n+\n+\tTAILQ_FOREACH_SAFE(flow, &hw->flow_list, next, temp) {\n+\t\tTAILQ_REMOVE(&hw->flow_list, flow, next);\n+\t\trte_free(flow);\n+\t}\n+\n+\treturn ipn3ke_flow_hw_flush(hw);\n+}\n+\n+int ipn3ke_flow_init(void *dev)\n+{\n+\tstruct ipn3ke_hw *hw = (struct ipn3ke_hw *)dev;\n+\tuint32_t data;\n+\n+\t/* disable rx classifier bypass */\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_RX_TEST,\n+\t\t\t0, 0, 0x1);\n+\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_RX_TEST,\n+\t\t\t\t0,\n+\t\t\t\t0x1);\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE_CLF_RX_TEST: %x\\n\", data);\n+\n+\t/* configure base mac address */\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_BASE_DST_MAC_ADDR_HI,\n+\t\t\t0,\n+\t\t\t0x2457,\n+\t\t\t0xFFFF);\n+\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_BASE_DST_MAC_ADDR_HI,\n+\t\t\t\t0,\n+\t\t\t\t0xFFFF);\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE_CLF_BASE_DST_MAC_ADDR_HI: %x\\n\", data);\n+\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_BASE_DST_MAC_ADDR_LOW,\n+\t\t\t0,\n+\t\t\t0x9bdf1000,\n+\t\t\t0xFFFFFFFF);\n+\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_BASE_DST_MAC_ADDR_LOW,\n+\t\t\t\t0,\n+\t\t\t\t0xFFFFFFFF);\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE_CLF_BASE_DST_MAC_ADDR_LOW: %x\\n\", data);\n+\n+\n+\t/* configure hash lookup rules enable */\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_LKUP_ENABLE,\n+\t\t\t0,\n+\t\t\t0xFD,\n+\t\t\t0xFF);\n+\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_LKUP_ENABLE,\n+\t\t\t\t0,\n+\t\t\t\t0xFF);\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE_CLF_LKUP_ENABLE: %x\\n\", data);\n+\n+\n+\t/* configure rx parse config, settings associatied with VxLAN */\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_RX_PARSE_CFG,\n+\t\t\t0,\n+\t\t\t0x212b5,\n+\t\t\t0x3FFFF);\n+\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_RX_PARSE_CFG,\n+\t\t\t\t0,\n+\t\t\t\t0x3FFFF);\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE_CLF_RX_PARSE_CFG: %x\\n\", data);\n+\n+\n+\t/* configure QinQ S-Tag */\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_QINQ_STAG,\n+\t\t\t0,\n+\t\t\t0x88a8,\n+\t\t\t0xFFFF);\n+\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_QINQ_STAG,\n+\t\t\t\t0,\n+\t\t\t\t0xFFFF);\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE_CLF_QINQ_STAG: %x\\n\", data);\n+\n+\n+\t/* configure gen ctrl */\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_MHL_GEN_CTRL,\n+\t\t\t0,\n+\t\t\t0x3,\n+\t\t\t0x3);\n+\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_MHL_GEN_CTRL,\n+\t\t\t\t0,\n+\t\t\t\t0x1F);\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE_CLF_MHL_GEN_CTRL: %x\\n\", data);\n+\n+\n+\t/* clear monitoring register */\n+\tIPN3KE_MASK_WRITE_REG(hw,\n+\t\t\tIPN3KE_CLF_MHL_MON_0,\n+\t\t\t0,\n+\t\t\t0xFFFFFFFF,\n+\t\t\t0xFFFFFFFF);\n+\n+\tdata = 0;\n+\tdata = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\tIPN3KE_CLF_MHL_MON_0,\n+\t\t\t\t0,\n+\t\t\t\t0xFFFFFFFF);\n+\tIPN3KE_AFU_PMD_DEBUG(\"IPN3KE_CLF_MHL_MON_0: %x\\n\", data);\n+\n+\n+\tipn3ke_flow_hw_flush(hw);\n+\n+\tTAILQ_INIT(&hw->flow_list);\n+\thw->flow_max_entries = IPN3KE_MASK_READ_REG(hw,\n+\t\t\t\t\t\tIPN3KE_CLF_EM_NUM,\n+\t\t\t\t\t\t0,\n+\t\t\t\t\t\t0xFFFFFFFF);\n+\thw->flow_num_entries = 0;\n+\n+\treturn 0;\n+}\n+\n+const struct rte_flow_ops ipn3ke_flow_ops = {\n+\t.validate = ipn3ke_flow_validate,\n+\t.create = ipn3ke_flow_create,\n+\t.destroy = ipn3ke_flow_destroy,\n+\t.flush = ipn3ke_flow_flush,\n+};\n+\ndiff --git a/drivers/net/ipn3ke/ipn3ke_flow.h b/drivers/net/ipn3ke/ipn3ke_flow.h\nnew file mode 100644\nindex 0000000..ef1a61f\n--- /dev/null\n+++ b/drivers/net/ipn3ke/ipn3ke_flow.h\n@@ -0,0 +1,106 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2019 Intel Corporation\n+ */\n+\n+#ifndef _IPN3KE_FLOW_H_\n+#define _IPN3KE_FLOW_H_\n+\n+/**\n+ * Expand the length to DWORD alignment with 'Unused' field.\n+ *\n+ * FLOW KEY:\n+ *  | Unused |Ruler id (id)  | Key1 Key2 … (data) |\n+ *  |--------+---------------+--------------------|\n+ *  | 17bits |    3 bits     |   Total 108 bits   |\n+ * MSB                 --->                      LSB\n+ *\n+ * Note: And the MSb of key data is filled to 0 when it is less\n+ *       than 108 bit.\n+ */\n+#define IPN3KE_FLOW_KEY_UNUSED_BITS  17\n+#define IPN3KE_FLOW_KEY_ID_BITS      3\n+#define IPN3KE_FLOW_KEY_DATA_BITS    108\n+\n+#define IPN3KE_FLOW_KEY_TOTAL_BITS \\\n+\t\t(IPN3KE_FLOW_KEY_UNUSED_BITS + \\\n+\t\tIPN3KE_FLOW_KEY_ID_BITS + \\\n+\t\tIPN3KE_FLOW_KEY_DATA_BITS)\n+\n+#define IPN3KE_FLOW_KEY_ID_OFFSET \\\n+\t\t(IPN3KE_FLOW_KEY_UNUSED_BITS)\n+\n+#define IPN3KE_FLOW_KEY_DATA_OFFSET \\\n+\t\t(IPN3KE_FLOW_KEY_ID_OFFSET + IPN3KE_FLOW_KEY_ID_BITS)\n+\n+/**\n+ * Expand the length to DWORD alignment with 'Unused' field.\n+ *\n+ * FLOW RESULT:\n+ *  |  Unused | enable (acl) |    uid       |\n+ *  |---------+--------------+--------------|\n+ *  | 15 bits |    1 bit     |   16 bits    |\n+ * MSB              --->                   LSB\n+ */\n+\n+#define IPN3KE_FLOW_RESULT_UNUSED_BITS 15\n+#define IPN3KE_FLOW_RESULT_ACL_BITS    1\n+#define IPN3KE_FLOW_RESULT_UID_BITS    16\n+\n+#define IPN3KE_FLOW_RESULT_TOTAL_BITS \\\n+\t\t(IPN3KE_FLOW_RESULT_UNUSED_BITS + \\\n+\t\tIPN3KE_FLOW_RESULT_ACL_BITS + \\\n+\t\tIPN3KE_FLOW_RESULT_UID_BITS)\n+\n+#define IPN3KE_FLOW_RESULT_ACL_OFFSET \\\n+\t\t(IPN3KE_FLOW_RESULT_UNUSED_BITS)\n+\n+#define IPN3KE_FLOW_RESULT_UID_OFFSET \\\n+\t\t(IPN3KE_FLOW_RESULT_ACL_OFFSET + IPN3KE_FLOW_RESULT_ACL_BITS)\n+\n+#define IPN3KE_FLOW_RESULT_UID_MAX \\\n+\t\t((1UL << IPN3KE_FLOW_RESULT_UID_BITS) - 1)\n+\n+#ifndef BITS_PER_BYTE\n+#define BITS_PER_BYTE    8\n+#endif\n+#define BITS_TO_BYTES(bits) \\\n+\t(((bits) + BITS_PER_BYTE - 1) / BITS_PER_BYTE)\n+\n+struct ipn3ke_flow_rule {\n+\tuint8_t key[BITS_TO_BYTES(IPN3KE_FLOW_KEY_TOTAL_BITS)];\n+\tuint8_t result[BITS_TO_BYTES(IPN3KE_FLOW_RESULT_TOTAL_BITS)];\n+};\n+\n+struct rte_flow {\n+\tTAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */\n+\n+\tstruct ipn3ke_flow_rule rule;\n+};\n+\n+TAILQ_HEAD(ipn3ke_flow_list, rte_flow);\n+\n+static inline uint16_t ipn3ke_swap16(uint16_t x)\n+{\n+\treturn ((x & 0xff) << 8) | ((x >> 8) & 0xff);\n+}\n+\n+static inline uint32_t ipn3ke_swap32(uint32_t x)\n+{\n+\tuint32_t high, low;\n+\tuint32_t high1, low1;\n+\n+\thigh = (x >> 16) & 0xffff;\n+\tlow = x & 0xffff;\n+\thigh1 = ipn3ke_swap16(low);\n+\thigh1 = high1 << 16;\n+\tlow1 = ipn3ke_swap16(high);\n+\tlow1 = low1 & 0xffff;\n+\n+\treturn high1 | low1;\n+}\n+\n+extern const struct rte_flow_ops ipn3ke_flow_ops;\n+\n+int ipn3ke_flow_init(void *dev);\n+\n+#endif /* _IPN3KE_FLOW_H_ */\ndiff --git a/drivers/net/ipn3ke/ipn3ke_representor.c b/drivers/net/ipn3ke/ipn3ke_representor.c\nindex 63098bf..cf3b214 100644\n--- a/drivers/net/ipn3ke/ipn3ke_representor.c\n+++ b/drivers/net/ipn3ke/ipn3ke_representor.c\n@@ -21,6 +21,7 @@\n #include <ifpga_logs.h>\n \n #include \"ipn3ke_rawdev_api.h\"\n+#include \"ipn3ke_flow.h\"\n #include \"ipn3ke_logs.h\"\n #include \"ipn3ke_ethdev.h\"\n \n@@ -746,7 +747,7 @@\n \t\tcase RTE_ETH_FILTER_GENERIC:\n \t\t\tif (filter_op != RTE_ETH_FILTER_GET)\n \t\t\t\treturn -EINVAL;\n-\t\t\t*(const void **)arg = NULL;\n+\t\t\t*(const void **)arg = &ipn3ke_flow_ops;\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tIPN3KE_AFU_PMD_WARN(\"Filter type (%d) not supported\",\ndiff --git a/drivers/net/ipn3ke/ipn3ke_tm.c b/drivers/net/ipn3ke/ipn3ke_tm.c\nindex 4ca4c97..ef87a41 100644\n--- a/drivers/net/ipn3ke/ipn3ke_tm.c\n+++ b/drivers/net/ipn3ke/ipn3ke_tm.c\n@@ -23,6 +23,7 @@\n #include <ifpga_logs.h>\n \n #include \"ipn3ke_rawdev_api.h\"\n+#include \"ipn3ke_flow.h\"\n #include \"ipn3ke_logs.h\"\n #include \"ipn3ke_ethdev.h\"\n \ndiff --git a/drivers/net/ipn3ke/meson.build b/drivers/net/ipn3ke/meson.build\nindex 3a95efc..74b4d7c 100644\n--- a/drivers/net/ipn3ke/meson.build\n+++ b/drivers/net/ipn3ke/meson.build\n@@ -12,5 +12,6 @@ allow_experimental_apis = true\n \n sources += files('ipn3ke_ethdev.c',\n \t'ipn3ke_representor.c',\n-\t'ipn3ke_tm.c')\n+\t'ipn3ke_tm.c',\n+\t'ipn3ke_flow.c')\n deps += ['bus_ifpga', 'sched']\n",
    "prefixes": [
        "v6",
        "06/14"
    ]
}