get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 68253,
    "url": "https://patches.dpdk.org/api/patches/68253/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20200413063037.13728-12-alvinx.zhang@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20200413063037.13728-12-alvinx.zhang@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200413063037.13728-12-alvinx.zhang@intel.com",
    "date": "2020-04-13T06:30:37",
    "name": "[v3,11/11] net/igc: implement flow API",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "bc7fd5238181d11e5fd31256a97171e256eaa08b",
    "submitter": {
        "id": 1398,
        "url": "https://patches.dpdk.org/api/people/1398/?format=api",
        "name": "Alvin Zhang",
        "email": "alvinx.zhang@intel.com"
    },
    "delegate": {
        "id": 319,
        "url": "https://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20200413063037.13728-12-alvinx.zhang@intel.com/mbox/",
    "series": [
        {
            "id": 9328,
            "url": "https://patches.dpdk.org/api/series/9328/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=9328",
            "date": "2020-04-13T06:30:26",
            "name": "igc pmd",
            "version": 3,
            "mbox": "https://patches.dpdk.org/series/9328/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/68253/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/68253/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 58989A0577;\n\tMon, 13 Apr 2020 08:34:25 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 791931C042;\n\tMon, 13 Apr 2020 08:31:53 +0200 (CEST)",
            "from mga12.intel.com (mga12.intel.com [192.55.52.136])\n by dpdk.org (Postfix) with ESMTP id 0DF671C022\n for <dev@dpdk.org>; Mon, 13 Apr 2020 08:31:48 +0200 (CEST)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 12 Apr 2020 23:31:48 -0700",
            "from shwdenpg235.ccr.corp.intel.com ([10.240.182.60])\n by orsmga002.jf.intel.com with ESMTP; 12 Apr 2020 23:31:46 -0700"
        ],
        "IronPort-SDR": [
            "\n 98q4/P5PouUBlfi45T/v03T43BKHrDnE7gXka83fHJGJ2sH15mEjTXlIV46MCvDuysGHcuZcVX\n udaVu0J6fxtg==",
            "\n bWmkeRc2/pWmXO6zPGlPwEUDQOrLIyp2iJTm26bX0Qv8XrP85iVAq2fX3DgX2mUCycq45nO00C\n i2MWVRRNCL6A=="
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.72,377,1580803200\"; d=\"scan'208\";a=\"270987708\"",
        "From": "alvinx.zhang@intel.com",
        "To": "dev@dpdk.org",
        "Cc": "xiaolong.ye@intel.com,\n\tAlvin Zhang <alvinx.zhang@intel.com>",
        "Date": "Mon, 13 Apr 2020 14:30:37 +0800",
        "Message-Id": "<20200413063037.13728-12-alvinx.zhang@intel.com>",
        "X-Mailer": "git-send-email 2.21.0.windows.1",
        "In-Reply-To": "<20200413063037.13728-1-alvinx.zhang@intel.com>",
        "References": "<20200413063037.13728-1-alvinx.zhang@intel.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v3 11/11] net/igc: implement flow API",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Alvin Zhang <alvinx.zhang@intel.com>\n\nBelow type of flows are supported:\nether-type filter, 2-tuple filter, SYN filter, RSS.\nUpdate docs too.\n\nSigned-off-by: Alvin Zhang <alvinx.zhang@intel.com>\n\nV2: Modify codes according to comments.\nV3: Remove legacy ether-type, 2-tuple and tcp SYN filters API,\n    add some examples of creating flow.\n---\n doc/guides/nics/features/igc.ini |   1 +\n doc/guides/nics/igc.rst          |  44 ++\n drivers/net/igc/Makefile         |   2 +\n drivers/net/igc/igc_ethdev.c     |   8 +\n drivers/net/igc/igc_ethdev.h     |  98 +++++\n drivers/net/igc/igc_filter.c     | 390 +++++++++++++++++\n drivers/net/igc/igc_filter.h     |  39 ++\n drivers/net/igc/igc_flow.c       | 917 +++++++++++++++++++++++++++++++++++++++\n drivers/net/igc/igc_flow.h       |  25 ++\n drivers/net/igc/igc_txrx.c       | 132 +++++-\n drivers/net/igc/igc_txrx.h       |   6 +\n drivers/net/igc/meson.build      |   4 +-\n 12 files changed, 1664 insertions(+), 2 deletions(-)\n create mode 100644 drivers/net/igc/igc_filter.c\n create mode 100644 drivers/net/igc/igc_filter.h\n create mode 100644 drivers/net/igc/igc_flow.c\n create mode 100644 drivers/net/igc/igc_flow.h",
    "diff": "diff --git a/doc/guides/nics/features/igc.ini b/doc/guides/nics/features/igc.ini\nindex 5bc901f..09300eb 100644\n--- a/doc/guides/nics/features/igc.ini\n+++ b/doc/guides/nics/features/igc.ini\n@@ -32,6 +32,7 @@ RSS key update       = Y\n RSS reta update      = Y\n VLAN filter          = Y\n VLAN offload         = Y\n+Flow API             = P\n Linux UIO            = Y\n Linux VFIO           = Y\n x86-64               = Y\ndiff --git a/doc/guides/nics/igc.rst b/doc/guides/nics/igc.rst\nindex 7ea6536..8e3cfa4 100644\n--- a/doc/guides/nics/igc.rst\n+++ b/doc/guides/nics/igc.rst\n@@ -75,3 +75,47 @@ outer VLAN to 0x9100:\n    testpmd> vlan set strip off 0\n    testpmd> vlan set extend on 0\n    testpmd> vlan set outer tpid 0x9100 0\n+\n+\n+Flow Director\n+~~~~~~~~~~~~~\n+\n+The Flow Director works in receive mode to identify specific flows or sets of flows and route\n+them to specific queues.\n+\n+The Flow Director filters includes the following types:\n+\n+- ether-type filter\n+- 2-tuple filter(destination L4 protocol and destination L4 port)\n+- TCP SYN filter\n+- RSS filter\n+\n+Start ``testpmd``:\n+\n+.. code-block:: console\n+\n+   ./testpmd -l 4-8 -- i --rxq=4 --txq=4 --pkt-filter-mode=perfect --disable-rss\n+\n+Add a rule to direct packet whose ``ether-type=0x801`` to queue 1:\n+\n+.. code-block:: console\n+\n+   testpmd> flow create 0 ingress pattern eth type is 0x801 / end actions queue index 1 / end\n+\n+Add a rule to direct packet whose ``ip-protocol=0x6(TCP), tcp_port=0x80`` to queue 1:\n+\n+.. code-block:: console\n+\n+   testpmd> flow create 0 ingress pattern eth / ipv4 proto is 6 / tcp dst is 0x80 / end actions queue index 1 / end\n+\n+Add a rule to direct packet whose ``ip-protocol=0x6(TCP), SYN flag is set`` to queue 1:\n+\n+.. code-block:: console\n+\n+   testpmd> flow validate 0 ingress pattern tcp flags spec 0x02 flags mask 0x02 / end actions queue index 1 / end\n+\n+Add a rule to enable ipv4-udp RSS:\n+\n+.. code-block:: console\n+\n+   testpmd> flow create 0 ingress pattern end actions rss types ipv4-udp end / end\ndiff --git a/drivers/net/igc/Makefile b/drivers/net/igc/Makefile\nindex c162c51..d6d7959 100644\n--- a/drivers/net/igc/Makefile\n+++ b/drivers/net/igc/Makefile\n@@ -34,5 +34,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += igc_phy.c\n SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += igc_logs.c\n SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += igc_ethdev.c\n SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += igc_txrx.c\n+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += igc_filter.c\n+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += igc_flow.c\n \n include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c\nindex 4d7c1e0..c64a5b2 100644\n--- a/drivers/net/igc/igc_ethdev.c\n+++ b/drivers/net/igc/igc_ethdev.c\n@@ -15,6 +15,8 @@\n \n #include \"igc_logs.h\"\n #include \"igc_txrx.h\"\n+#include \"igc_filter.h\"\n+#include \"igc_flow.h\"\n \n #define IGC_INTEL_VENDOR_ID\t\t0x8086\n \n@@ -299,6 +301,7 @@ static int eth_igc_vlan_tpid_set(struct rte_eth_dev *dev,\n \t.vlan_offload_set\t= eth_igc_vlan_offload_set,\n \t.vlan_tpid_set\t\t= eth_igc_vlan_tpid_set,\n \t.vlan_strip_queue_set\t= eth_igc_vlan_strip_queue_set,\n+\t.filter_ctrl\t\t= eth_igc_filter_ctrl,\n };\n \n /*\n@@ -1180,6 +1183,9 @@ static int eth_igc_vlan_tpid_set(struct rte_eth_dev *dev,\n \tif (!adapter->stopped)\n \t\teth_igc_stop(dev);\n \n+\tigc_flow_flush(dev, NULL);\n+\tigc_clear_all_filter(dev);\n+\n \tigc_intr_other_disable(dev);\n \tdo {\n \t\tint ret = rte_intr_callback_unregister(intr_handle,\n@@ -1348,6 +1354,8 @@ static int eth_igc_vlan_tpid_set(struct rte_eth_dev *dev,\n \t\tigc->rxq_stats_map[i] = -1;\n \t}\n \n+\tigc_flow_init(dev);\n+\tigc_clear_all_filter(dev);\n \treturn 0;\n \n err_late:\ndiff --git a/drivers/net/igc/igc_ethdev.h b/drivers/net/igc/igc_ethdev.h\nindex 4b84127..a09debf 100644\n--- a/drivers/net/igc/igc_ethdev.h\n+++ b/drivers/net/igc/igc_ethdev.h\n@@ -90,6 +90,19 @@\n \tETH_RSS_IPV6_TCP_EX        | \\\n \tETH_RSS_IPV6_UDP_EX)\n \n+#define IGC_MAX_ETQF_FILTERS\t\t3\t/* etqf(3) is used for 1588 */\n+#define IGC_ETQF_FILTER_1588\t\t3\n+#define IGC_ETQF_QUEUE_SHIFT\t\t16\n+#define IGC_ETQF_QUEUE_MASK\t\t(7u << IGC_ETQF_QUEUE_SHIFT)\n+\n+#define IGC_MAX_NTUPLE_FILTERS\t\t8\n+#define IGC_NTUPLE_MAX_PRI\t\t7\n+\n+#define IGC_SYN_FILTER_ENABLE\t\t0x01\t/* syn filter enable field */\n+#define IGC_SYN_FILTER_QUEUE_SHIFT\t1\t/* syn filter queue field */\n+#define IGC_SYN_FILTER_QUEUE\t0x0000000E\t/* syn filter queue field */\n+#define IGC_RFCTL_SYNQFP\t0x00080000\t/* SYNQFP in RFCTL register */\n+\n /* structure for interrupt relative data */\n struct igc_interrupt {\n \tuint32_t flags;\n@@ -125,6 +138,79 @@ struct igc_vfta {\n \tuint32_t vfta[IGC_VFTA_SIZE];\n };\n \n+/* ethertype filter structure */\n+struct igc_ethertype_filter {\n+\tuint16_t ether_type;\n+\tuint16_t queue;\n+};\n+\n+/* Structure of ntuple filter info. */\n+struct igc_ntuple_info {\n+\tuint16_t dst_port;\n+\tuint8_t proto;\t\t/* l4 protocol. */\n+\n+\t/*\n+\t * the packet matched above 2tuple and contain any set bit will hit\n+\t * this filter.\n+\t */\n+\tuint8_t tcp_flags;\n+\n+\t/*\n+\t * seven levels (001b-111b), 111b is highest, used when more than one\n+\t * filter matches.\n+\t */\n+\tuint8_t priority;\n+\tuint8_t dst_port_mask:1, /* if mask is 1b, do compare dst port. */\n+\t\tproto_mask:1;    /* if mask is 1b, do compare protocol. */\n+};\n+\n+/* Structure of n-tuple filter */\n+struct igc_ntuple_filter {\n+\tRTE_STD_C11\n+\tunion {\n+\t\tuint64_t hash_val;\n+\t\tstruct igc_ntuple_info tuple_info;\n+\t};\n+\n+\tuint8_t queue;\n+};\n+\n+/* Structure of TCP SYN filter */\n+struct igc_syn_filter {\n+\tuint8_t queue;\n+\n+\tuint8_t hig_pri:1,\t/* 1 - higher priority than other filters, */\n+\t\t\t\t/* 0 - lower priority. */\n+\t\tenable:1;\t/* 1-enable; 0-disable */\n+};\n+\n+/* Structure to store RTE flow RSS configure. */\n+struct igc_rss_filter {\n+\tstruct rte_flow_action_rss conf; /* RSS parameters. */\n+\tuint8_t key[IGC_HKEY_MAX_INDEX * sizeof(uint32_t)]; /* Hash key. */\n+\tuint16_t queue[IGC_RSS_RDT_SIZD];/* Queues indices to use. */\n+\tuint8_t enable;\t/* 1-enabled, 0-disabled */\n+};\n+\n+/* Feature filter types */\n+enum igc_filter_type {\n+\tIGC_FILTER_TYPE_ETHERTYPE,\n+\tIGC_FILTER_TYPE_NTUPLE,\n+\tIGC_FILTER_TYPE_SYN,\n+\tIGC_FILTER_TYPE_HASH\n+};\n+\n+/* Structure to store flow */\n+struct rte_flow {\n+\tTAILQ_ENTRY(rte_flow) node;\n+\tenum igc_filter_type filter_type;\n+\tRTE_STD_C11\n+\tchar filter[0];\t\t/* filter data */\n+};\n+\n+/* Flow list header */\n+TAILQ_HEAD(igc_flow_list, rte_flow);\n+\n /*\n  * Structure to store private data for each driver instance (for each port).\n  */\n@@ -138,6 +224,12 @@ struct igc_adapter {\n \tstruct igc_interrupt\tintr;\n \tstruct igc_vfta\tshadow_vfta;\n \tbool\t\tstopped;\n+\n+\tstruct igc_ethertype_filter ethertype_filters[IGC_MAX_ETQF_FILTERS];\n+\tstruct igc_ntuple_filter ntuple_filters[IGC_MAX_NTUPLE_FILTERS];\n+\tstruct igc_syn_filter syn_filter;\n+\tstruct igc_rss_filter rss_filter;\n+\tstruct igc_flow_list flow_list;\n };\n \n #define IGC_DEV_PRIVATE(_dev)\t((_dev)->data->dev_private)\n@@ -157,6 +249,12 @@ struct igc_adapter {\n #define IGC_DEV_PRIVATE_VFTA(_dev) \\\n \t(&((struct igc_adapter *)(_dev)->data->dev_private)->shadow_vfta)\n \n+#define IGC_DEV_PRIVATE_RSS_FILTER(_dev) \\\n+\t(&((struct igc_adapter *)(_dev)->data->dev_private)->rss_filter)\n+\n+#define IGC_DEV_PRIVATE_FLOW_LIST(_dev) \\\n+\t(&((struct igc_adapter *)(_dev)->data->dev_private)->flow_list)\n+\n static inline void\n igc_read_reg_check_set_bits(struct igc_hw *hw, uint32_t reg, uint32_t bits)\n {\ndiff --git a/drivers/net/igc/igc_filter.c b/drivers/net/igc/igc_filter.c\nnew file mode 100644\nindex 0000000..149910f\n--- /dev/null\n+++ b/drivers/net/igc/igc_filter.c\n@@ -0,0 +1,390 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2020 Intel Corporation\n+ */\n+\n+#include \"rte_malloc.h\"\n+#include \"igc_logs.h\"\n+#include \"igc_txrx.h\"\n+#include \"igc_filter.h\"\n+#include \"igc_flow.h\"\n+\n+/*\n+ * igc_ethertype_filter_lookup - lookup ether-type filter\n+ *\n+ * @igc, IGC filter pointer\n+ * @ethertype, ethernet type\n+ * @empty, a place to store the index of empty entry if the item not found\n+ *  it's not smaller than 0 if valid, otherwise -1 for no empty entry.\n+ *  empty parameter is only valid if the return value of the function is -1\n+ *\n+ * Return value\n+ * >= 0, item index of the ether-type filter\n+ * -1, the item not been found\n+ */\n+static inline int\n+igc_ethertype_filter_lookup(const struct igc_adapter *igc,\n+\t\t\tuint16_t ethertype, int *empty)\n+{\n+\tint i = 0;\n+\n+\tif (empty) {\n+\t\t/* set to invalid valid */\n+\t\t*empty = -1;\n+\n+\t\t/* search the filters array */\n+\t\tfor (; i < IGC_MAX_ETQF_FILTERS; i++) {\n+\t\t\tif (igc->ethertype_filters[i].ether_type == ethertype)\n+\t\t\t\treturn i;\n+\t\t\tif (igc->ethertype_filters[i].ether_type == 0) {\n+\t\t\t\t/* get empty entry */\n+\t\t\t\t*empty = i;\n+\t\t\t\ti++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* search the rest of filters */\n+\tfor (; i < IGC_MAX_ETQF_FILTERS; i++) {\n+\t\tif (igc->ethertype_filters[i].ether_type == ethertype)\n+\t\t\treturn i;\t/* filter be found, return index */\n+\t}\n+\n+\treturn -1;\n+}\n+\n+int\n+igc_del_ethertype_filter(struct rte_eth_dev *dev,\n+\t\t\tconst struct igc_ethertype_filter *filter)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct igc_adapter *igc = IGC_DEV_PRIVATE(dev);\n+\tint ret;\n+\n+\tif (filter->ether_type == 0) {\n+\t\tPMD_DRV_LOG(ERR, \"ethertype 0 is not been supported\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tret = igc_ethertype_filter_lookup(igc, filter->ether_type, NULL);\n+\tif (ret < 0) {\n+\t\t/* not found */\n+\t\tPMD_DRV_LOG(ERR, \"ethertype (0x%04x) filter doesn't\"\n+\t\t\t\" exist.\", filter->ether_type);\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tigc->ethertype_filters[ret].ether_type = 0;\n+\n+\tIGC_WRITE_REG(hw, IGC_ETQF(ret), 0);\n+\tIGC_WRITE_FLUSH(hw);\n+\treturn 0;\n+}\n+\n+int\n+igc_add_ethertype_filter(struct rte_eth_dev *dev,\n+\t\t\tconst struct igc_ethertype_filter *filter)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct igc_adapter *igc = IGC_DEV_PRIVATE(dev);\n+\tuint32_t etqf;\n+\tint ret, empty;\n+\n+\tif (filter->ether_type == RTE_ETHER_TYPE_IPV4 ||\n+\t\tfilter->ether_type == RTE_ETHER_TYPE_IPV6 ||\n+\t\tfilter->ether_type == 0) {\n+\t\tPMD_DRV_LOG(ERR, \"unsupported ether_type(0x%04x) in\"\n+\t\t\t\" ethertype filter.\", filter->ether_type);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tret = igc_ethertype_filter_lookup(igc, filter->ether_type, &empty);\n+\tif (ret >= 0) {\n+\t\tPMD_DRV_LOG(ERR, \"ethertype (0x%04x) filter exists.\",\n+\t\t\t\tfilter->ether_type);\n+\t\treturn -EEXIST;\n+\t}\n+\n+\tif (empty < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"no ethertype filter entry.\");\n+\t\treturn -ENOSPC;\n+\t}\n+\tret = empty;\n+\n+\tetqf = filter->ether_type;\n+\tetqf |= IGC_ETQF_FILTER_ENABLE | IGC_ETQF_QUEUE_ENABLE;\n+\tetqf |= (uint32_t)filter->queue << IGC_ETQF_QUEUE_SHIFT;\n+\n+\tmemcpy(&igc->ethertype_filters[ret], filter, sizeof(*filter));\n+\n+\tIGC_WRITE_REG(hw, IGC_ETQF(ret), etqf);\n+\tIGC_WRITE_FLUSH(hw);\n+\treturn 0;\n+}\n+\n+/* clear all the ether type filters */\n+static void\n+igc_clear_all_ethertype_filter(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct igc_adapter *igc = IGC_DEV_PRIVATE(dev);\n+\tint i;\n+\n+\tfor (i = 0; i < IGC_MAX_ETQF_FILTERS; i++)\n+\t\tIGC_WRITE_REG(hw, IGC_ETQF(i), 0);\n+\tIGC_WRITE_FLUSH(hw);\n+\n+\tmemset(&igc->ethertype_filters, 0, sizeof(igc->ethertype_filters));\n+}\n+\n+/*\n+ * igc_tuple_filter_lookup - lookup n-tuple filter\n+ *\n+ * @igc, igc filter pointer\n+ * @ntuple, n-tuple filter pointer\n+ * @empty, a place to store the index of empty entry if the item not found\n+ *  it's not smaller than 0 if valid, otherwise -1 for no empty entry.\n+ *  The value of empty is uncertain if the return value of the function is\n+ *  not -1.\n+ *\n+ * Return value\n+ * >= 0, item index of the filter\n+ * -1, the item not been found\n+ */\n+static int\n+igc_tuple_filter_lookup(const struct igc_adapter *igc,\n+\t\t\tconst struct igc_ntuple_filter *ntuple,\n+\t\t\tint *empty)\n+{\n+\tint i = 0;\n+\n+\tif (empty) {\n+\t\t/* set initial value */\n+\t\t*empty = -1;\n+\n+\t\t/* search the filter array */\n+\t\tfor (; i < IGC_MAX_NTUPLE_FILTERS; i++) {\n+\t\t\tif (igc->ntuple_filters[i].hash_val) {\n+\t\t\t\t/* compare the hase value */\n+\t\t\t\tif (ntuple->hash_val ==\n+\t\t\t\t\tigc->ntuple_filters[i].hash_val)\n+\t\t\t\t\t/* filter be found, return index */\n+\t\t\t\t\treturn i;\n+\t\t\t} else {\n+\t\t\t\t/* get the empty entry */\n+\t\t\t\t*empty = i;\n+\t\t\t\ti++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* search the rest of filters */\n+\tfor (; i < IGC_MAX_NTUPLE_FILTERS; i++) {\n+\t\tif (ntuple->hash_val == igc->ntuple_filters[i].hash_val)\n+\t\t\t/* filter be found, return index */\n+\t\t\treturn i;\n+\t}\n+\n+\treturn -1;\n+}\n+\n+/* Set hardware register values */\n+static void\n+igc_enable_tuple_filter(struct rte_eth_dev *dev,\n+\t\t\tconst struct igc_adapter *igc, uint8_t index)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tconst struct igc_ntuple_filter *filter = &igc->ntuple_filters[index];\n+\tconst struct igc_ntuple_info *info = &filter->tuple_info;\n+\tuint32_t ttqf, imir, imir_ext = IGC_IMIREXT_SIZE_BP;\n+\n+\timir = info->dst_port;\n+\timir |= (uint32_t)info->priority << IGC_IMIR_PRIORITY_SHIFT;\n+\n+\t/* 0b means not compare. */\n+\tif (info->dst_port_mask == 0)\n+\t\timir |= IGC_IMIR_PORT_BP;\n+\n+\tttqf = IGC_TTQF_DISABLE_MASK | IGC_TTQF_QUEUE_ENABLE;\n+\tttqf |= (uint32_t)filter->queue << IGC_TTQF_QUEUE_SHIFT;\n+\tttqf |= info->proto;\n+\n+\tif (info->proto_mask)\n+\t\tttqf &= ~IGC_TTQF_MASK_ENABLE;\n+\n+\t/* TCP flags bits setting. */\n+\tif (info->tcp_flags & RTE_NTUPLE_TCP_FLAGS_MASK) {\n+\t\tif (info->tcp_flags & RTE_TCP_URG_FLAG)\n+\t\t\timir_ext |= IGC_IMIREXT_CTRL_URG;\n+\t\tif (info->tcp_flags & RTE_TCP_ACK_FLAG)\n+\t\t\timir_ext |= IGC_IMIREXT_CTRL_ACK;\n+\t\tif (info->tcp_flags & RTE_TCP_PSH_FLAG)\n+\t\t\timir_ext |= IGC_IMIREXT_CTRL_PSH;\n+\t\tif (info->tcp_flags & RTE_TCP_RST_FLAG)\n+\t\t\timir_ext |= IGC_IMIREXT_CTRL_RST;\n+\t\tif (info->tcp_flags & RTE_TCP_SYN_FLAG)\n+\t\t\timir_ext |= IGC_IMIREXT_CTRL_SYN;\n+\t\tif (info->tcp_flags & RTE_TCP_FIN_FLAG)\n+\t\t\timir_ext |= IGC_IMIREXT_CTRL_FIN;\n+\t} else {\n+\t\timir_ext |= IGC_IMIREXT_CTRL_BP;\n+\t}\n+\n+\tIGC_WRITE_REG(hw, IGC_IMIR(index), imir);\n+\tIGC_WRITE_REG(hw, IGC_TTQF(index), ttqf);\n+\tIGC_WRITE_REG(hw, IGC_IMIREXT(index), imir_ext);\n+\tIGC_WRITE_FLUSH(hw);\n+}\n+\n+/* Reset hardware register values */\n+static void\n+igc_disable_tuple_filter(struct rte_eth_dev *dev, uint8_t index)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\n+\tIGC_WRITE_REG(hw, IGC_TTQF(index), IGC_TTQF_DISABLE_MASK);\n+\tIGC_WRITE_REG(hw, IGC_IMIR(index), 0);\n+\tIGC_WRITE_REG(hw, IGC_IMIREXT(index), 0);\n+\tIGC_WRITE_FLUSH(hw);\n+}\n+\n+int\n+igc_add_ntuple_filter(struct rte_eth_dev *dev,\n+\t\tconst struct igc_ntuple_filter *ntuple)\n+{\n+\tstruct igc_adapter *igc = IGC_DEV_PRIVATE(dev);\n+\tint ret, empty;\n+\n+\tret = igc_tuple_filter_lookup(igc, ntuple, &empty);\n+\tif (ret >= 0) {\n+\t\tPMD_DRV_LOG(ERR, \"filter exists.\");\n+\t\treturn -EEXIST;\n+\t}\n+\n+\tif (empty < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"filter no entry.\");\n+\t\treturn -ENOSPC;\n+\t}\n+\n+\tret = empty;\n+\tmemcpy(&igc->ntuple_filters[ret], ntuple, sizeof(*ntuple));\n+\tigc_enable_tuple_filter(dev, igc, (uint8_t)ret);\n+\treturn 0;\n+}\n+\n+int\n+igc_del_ntuple_filter(struct rte_eth_dev *dev,\n+\t\tconst struct igc_ntuple_filter *ntuple)\n+{\n+\tstruct igc_adapter *igc = IGC_DEV_PRIVATE(dev);\n+\tint ret;\n+\n+\tret = igc_tuple_filter_lookup(igc, ntuple, NULL);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"filter not exists.\");\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tmemset(&igc->ntuple_filters[ret], 0, sizeof(*ntuple));\n+\tigc_disable_tuple_filter(dev, (uint8_t)ret);\n+\treturn 0;\n+}\n+\n+/* Clear all the n-tuple filters */\n+static void\n+igc_clear_all_ntuple_filter(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_adapter *igc = IGC_DEV_PRIVATE(dev);\n+\tint i;\n+\n+\tfor (i = 0; i < IGC_MAX_NTUPLE_FILTERS; i++)\n+\t\tigc_disable_tuple_filter(dev, i);\n+\n+\tmemset(&igc->ntuple_filters, 0, sizeof(igc->ntuple_filters));\n+}\n+\n+int\n+igc_set_syn_filter(struct rte_eth_dev *dev,\n+\t\tconst struct igc_syn_filter *filter)\n+{\n+\tstruct igc_hw *hw;\n+\tstruct igc_adapter *igc;\n+\tuint32_t synqf, rfctl;\n+\n+\tif (filter->queue >= IGC_QUEUE_PAIRS_NUM) {\n+\t\tPMD_DRV_LOG(ERR, \"out of range queue %u(max is %u)\",\n+\t\t\tfilter->queue, IGC_QUEUE_PAIRS_NUM);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tigc = IGC_DEV_PRIVATE(dev);\n+\n+\tif (igc->syn_filter.enable) {\n+\t\tPMD_DRV_LOG(ERR, \"SYN filter has been enabled before!\");\n+\t\treturn -EEXIST;\n+\t}\n+\n+\thw = IGC_DEV_PRIVATE_HW(dev);\n+\tsynqf = (uint32_t)filter->queue << IGC_SYN_FILTER_QUEUE_SHIFT;\n+\tsynqf |= IGC_SYN_FILTER_ENABLE;\n+\n+\trfctl = IGC_READ_REG(hw, IGC_RFCTL);\n+\tif (filter->hig_pri)\n+\t\trfctl |= IGC_RFCTL_SYNQFP;\n+\telse\n+\t\trfctl &= ~IGC_RFCTL_SYNQFP;\n+\n+\tmemcpy(&igc->syn_filter, filter, sizeof(igc->syn_filter));\n+\tigc->syn_filter.enable = 1;\n+\n+\tIGC_WRITE_REG(hw, IGC_RFCTL, rfctl);\n+\tIGC_WRITE_REG(hw, IGC_SYNQF(0), synqf);\n+\tIGC_WRITE_FLUSH(hw);\n+\treturn 0;\n+}\n+\n+/* clear the SYN filter */\n+void\n+igc_clear_syn_filter(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct igc_adapter *igc = IGC_DEV_PRIVATE(dev);\n+\n+\tIGC_WRITE_REG(hw, IGC_SYNQF(0), 0);\n+\tIGC_WRITE_FLUSH(hw);\n+\n+\tmemset(&igc->syn_filter, 0, sizeof(igc->syn_filter));\n+}\n+\n+void\n+igc_clear_all_filter(struct rte_eth_dev *dev)\n+{\n+\tigc_clear_all_ethertype_filter(dev);\n+\tigc_clear_all_ntuple_filter(dev);\n+\tigc_clear_syn_filter(dev);\n+\tigc_clear_rss_filter(dev);\n+}\n+\n+int\n+eth_igc_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,\n+\t\tenum rte_filter_op filter_op, void *arg)\n+{\n+\tint ret = 0;\n+\n+\tRTE_SET_USED(dev);\n+\n+\tswitch (filter_type) {\n+\tcase RTE_ETH_FILTER_GENERIC:\n+\t\tif (filter_op != RTE_ETH_FILTER_GET)\n+\t\t\treturn -EINVAL;\n+\t\t*(const void **)arg = &igc_flow_ops;\n+\t\tbreak;\n+\tdefault:\n+\t\tPMD_DRV_LOG(WARNING, \"Filter type (%d) not supported\",\n+\t\t\t\t\t\t\tfilter_type);\n+\t\tret = -EINVAL;\n+\t}\n+\n+\treturn ret;\n+}\ndiff --git a/drivers/net/igc/igc_filter.h b/drivers/net/igc/igc_filter.h\nnew file mode 100644\nindex 0000000..7995150\n--- /dev/null\n+++ b/drivers/net/igc/igc_filter.h\n@@ -0,0 +1,39 @@\n+/*\n+ * SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2020 Intel Corporation\n+ */\n+\n+#ifndef _IGC_FILTER_H_\n+#define _IGC_FILTER_H_\n+\n+#include <rte_ethdev.h>\n+#include <rte_ethdev_core.h>\n+#include <rte_eth_ctrl.h>\n+\n+#include \"igc_ethdev.h\"\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+int igc_add_ethertype_filter(struct rte_eth_dev *dev,\n+\t\tconst struct igc_ethertype_filter *filter);\n+int igc_del_ethertype_filter(struct rte_eth_dev *dev,\n+\t\tconst struct igc_ethertype_filter *filter);\n+int igc_add_ntuple_filter(struct rte_eth_dev *dev,\n+\t\tconst struct igc_ntuple_filter *tuple);\n+int igc_del_ntuple_filter(struct rte_eth_dev *dev,\n+\t\tconst struct igc_ntuple_filter *tuple);\n+int igc_set_syn_filter(struct rte_eth_dev *dev,\n+\t\tconst struct igc_syn_filter *filter);\n+void igc_clear_syn_filter(struct rte_eth_dev *dev);\n+void igc_clear_all_filter(struct rte_eth_dev *dev);\n+int\n+eth_igc_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,\n+\t\tenum rte_filter_op filter_op, void *arg);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* IGC_FILTER_H_ */\ndiff --git a/drivers/net/igc/igc_flow.c b/drivers/net/igc/igc_flow.c\nnew file mode 100644\nindex 0000000..1bb64d3\n--- /dev/null\n+++ b/drivers/net/igc/igc_flow.c\n@@ -0,0 +1,917 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2020 Intel Corporation\n+ */\n+\n+#include \"rte_malloc.h\"\n+#include \"igc_logs.h\"\n+#include \"igc_txrx.h\"\n+#include \"igc_filter.h\"\n+#include \"igc_flow.h\"\n+\n+/*******************************************************************************\n+ * All Supported Rule Type\n+ *\n+ * Notes:\n+ * `para` or `(para)`, the para must been set\n+ * `[para]`, the para is optional\n+ * `([para1][para2]...)`, all paras is optional, but must one of them been set\n+ * `para1 | para2 | ...`, only one of the paras can be set\n+ *\n+ * ether-type filter\n+ * pattern: ETH(type)/END\n+ * action: QUEUE/END\n+ * attribute:\n+ *\n+ * n-tuple filter\n+ * pattern: [ETH/]([IPv4(protocol)|IPv6(protocol)/][UDP(dst_port)|\n+ *          TCP([dst_port],[flags])|SCTP(dst_port)/])END\n+ * action: QUEUE/END\n+ * attribute: [priority(0-7)]\n+ *\n+ * SYN filter\n+ * pattern: [ETH/][IPv4|IPv6/]TCP(flags=SYN)/END\n+ * action: QUEUE/END\n+ * attribute: [priority(0,1)]\n+ *\n+ * RSS filter\n+ * pattern:\n+ * action: RSS/END\n+ * attribute:\n+ ******************************************************************************/\n+\n+/* Structure to store all filters */\n+struct igc_all_filter {\n+\tstruct igc_ethertype_filter ethertype;\n+\tstruct igc_ntuple_filter ntuple;\n+\tstruct igc_syn_filter syn;\n+\tstruct igc_rss_filter rss;\n+\tuint32_t\tmask;\t/* see IGC_FILTER_MASK_* definition */\n+};\n+\n+#define IGC_FILTER_MASK_ETHER\t\t(1u << IGC_FILTER_TYPE_ETHERTYPE)\n+#define IGC_FILTER_MASK_NTUPLE\t\t(1u << IGC_FILTER_TYPE_NTUPLE)\n+#define IGC_FILTER_MASK_TCP_SYN\t\t(1u << IGC_FILTER_TYPE_SYN)\n+#define IGC_FILTER_MASK_RSS\t\t(1u << IGC_FILTER_TYPE_HASH)\n+#define IGC_FILTER_MASK_ALL\t\t(IGC_FILTER_MASK_ETHER |\t\\\n+\t\t\t\t\tIGC_FILTER_MASK_NTUPLE |\t\\\n+\t\t\t\t\tIGC_FILTER_MASK_TCP_SYN |\t\\\n+\t\t\t\t\tIGC_FILTER_MASK_RSS)\n+\n+#define IGC_SET_FILTER_MASK(_filter, _mask_bits)\t\t\t\\\n+\t\t\t\t\t((_filter)->mask &= (_mask_bits))\n+\n+#define IGC_IS_ALL_BITS_SET(_val)\t((_val) == (typeof(_val))~0)\n+#define IGC_NOT_ALL_BITS_SET(_val)\t((_val) != (typeof(_val))~0)\n+\n+/* Parse rule attribute */\n+static int\n+igc_parse_attribute(const struct rte_flow_attr *attr,\n+\tstruct igc_all_filter *filter, struct rte_flow_error *error)\n+{\n+\tif (!attr)\n+\t\treturn 0;\n+\n+\tif (attr->group)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr,\n+\t\t\t\t\"Not support\");\n+\n+\tif (attr->egress)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attr,\n+\t\t\t\t\"Not support\");\n+\n+\tif (attr->transfer)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, attr,\n+\t\t\t\t\"Not support\");\n+\n+\tif (!attr->ingress)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_INGRESS, attr,\n+\t\t\t\t\"A rule must apply to ingress traffic\");\n+\n+\tif (attr->priority == 0)\n+\t\treturn 0;\n+\n+\t/* only n-tuple and SYN filter have priority level */\n+\tIGC_SET_FILTER_MASK(filter,\n+\t\tIGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);\n+\n+\tif (IGC_IS_ALL_BITS_SET(attr->priority)) {\n+\t\t/* only SYN filter match this value */\n+\t\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_TCP_SYN);\n+\t\tfilter->syn.hig_pri = 1;\n+\t\treturn 0;\n+\t}\n+\n+\tif (attr->priority > IGC_NTUPLE_MAX_PRI)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, attr,\n+\t\t\t\t\"Priority value is invalid.\");\n+\n+\tif (attr->priority > 1) {\n+\t\t/* only n-tuple filter match this value */\n+\t\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);\n+\n+\t\t/* get priority */\n+\t\tfilter->ntuple.tuple_info.priority = (uint8_t)attr->priority;\n+\t\treturn 0;\n+\t}\n+\n+\t/* get priority */\n+\tfilter->ntuple.tuple_info.priority = (uint8_t)attr->priority;\n+\tfilter->syn.hig_pri = (uint8_t)attr->priority;\n+\n+\treturn 0;\n+}\n+\n+/* function type of parse pattern */\n+typedef int (*igc_pattern_parse)(const struct rte_flow_item *,\n+\t\tstruct igc_all_filter *, struct rte_flow_error *);\n+\n+static int igc_parse_pattern_void(__rte_unused const struct rte_flow_item *item,\n+\t\t__rte_unused struct igc_all_filter *filter,\n+\t\t__rte_unused struct rte_flow_error *error);\n+static int igc_parse_pattern_ether(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter, struct rte_flow_error *error);\n+static int igc_parse_pattern_ip(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter, struct rte_flow_error *error);\n+static int igc_parse_pattern_ipv6(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter, struct rte_flow_error *error);\n+static int igc_parse_pattern_udp(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter, struct rte_flow_error *error);\n+static int igc_parse_pattern_tcp(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter, struct rte_flow_error *error);\n+\n+static igc_pattern_parse pattern_parse_list[] = {\n+\t\t[RTE_FLOW_ITEM_TYPE_VOID] = igc_parse_pattern_void,\n+\t\t[RTE_FLOW_ITEM_TYPE_ETH] = igc_parse_pattern_ether,\n+\t\t[RTE_FLOW_ITEM_TYPE_IPV4] = igc_parse_pattern_ip,\n+\t\t[RTE_FLOW_ITEM_TYPE_IPV6] = igc_parse_pattern_ipv6,\n+\t\t[RTE_FLOW_ITEM_TYPE_UDP] = igc_parse_pattern_udp,\n+\t\t[RTE_FLOW_ITEM_TYPE_TCP] = igc_parse_pattern_tcp,\n+};\n+\n+/* Parse rule patterns */\n+static int\n+igc_parse_patterns(const struct rte_flow_item patterns[],\n+\tstruct igc_all_filter *filter, struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item *item = patterns;\n+\n+\tif (item == NULL) {\n+\t\t/* only RSS filter match this pattern */\n+\t\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_RSS);\n+\t\treturn 0;\n+\t}\n+\n+\tfor (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tint ret;\n+\n+\t\tif (item->type >= RTE_DIM(pattern_parse_list))\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\t\"Not been supported\");\n+\n+\t\tif (item->last)\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_LAST, item,\n+\t\t\t\t\t\"Range not been supported\");\n+\n+\t\t/* check pattern format is valid */\n+\t\tif (!!item->spec ^ !!item->mask)\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\t\"Format error\");\n+\n+\t\t/* get the pattern type callback */\n+\t\tigc_pattern_parse parse_func =\n+\t\t\t\tpattern_parse_list[item->type];\n+\t\tif (!parse_func)\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\t\"Not been supported\");\n+\n+\t\t/* call the pattern type function */\n+\t\tret = parse_func(item, filter, error);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\t/* if no filter match the pattern */\n+\t\tif (filter->mask == 0)\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\t\"Not been supported\");\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int igc_parse_action_queue(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_action *act,\n+\t\tstruct igc_all_filter *filter, struct rte_flow_error *error);\n+static int igc_parse_action_rss(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_action *act,\n+\t\tstruct igc_all_filter *filter, struct rte_flow_error *error);\n+\n+/* Parse flow actions */\n+static int\n+igc_parse_actions(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_action actions[],\n+\t\tstruct igc_all_filter *filter,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_action *act = actions;\n+\tint ret;\n+\n+\tif (act == NULL)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_NUM, act,\n+\t\t\t\t\"Action is needed\");\n+\n+\tfor (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {\n+\t\tswitch (act->type) {\n+\t\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n+\t\t\tret = igc_parse_action_queue(dev, act, filter, error);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n+\t\t\tret = igc_parse_action_rss(dev, act, filter, error);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_VOID:\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, act,\n+\t\t\t\t\t\"Not been supported\");\n+\t\t}\n+\n+\t\t/* if no filter match the action */\n+\t\tif (filter->mask == 0)\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION, act,\n+\t\t\t\t\t\"Not been supported\");\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* Parse a flow rule */\n+static int\n+igc_parse_flow(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_attr *attr,\n+\t\tconst struct rte_flow_item patterns[],\n+\t\tconst struct rte_flow_action actions[],\n+\t\tstruct rte_flow_error *error,\n+\t\tstruct igc_all_filter *filter)\n+{\n+\tint ret;\n+\n+\t/* clear all filters */\n+\tmemset(filter, 0, sizeof(*filter));\n+\n+\t/* set default filter mask */\n+\tfilter->mask = IGC_FILTER_MASK_ALL;\n+\n+\tret = igc_parse_attribute(attr, filter, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = igc_parse_patterns(patterns, filter, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = igc_parse_actions(dev, actions, filter, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* if no or more than one filter matched this flow */\n+\tif (filter->mask == 0 || (filter->mask & (filter->mask - 1)))\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, NULL,\n+\t\t\t\t\"Flow can't be recognized\");\n+\treturn 0;\n+}\n+\n+/* Parse pattern type of void */\n+static int\n+igc_parse_pattern_void(__rte_unused const struct rte_flow_item *item,\n+\t\t__rte_unused struct igc_all_filter *filter,\n+\t\t__rte_unused struct rte_flow_error *error)\n+{\n+\treturn 0;\n+}\n+\n+/* Parse pattern type of ethernet header */\n+static int\n+igc_parse_pattern_ether(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_eth *spec = item->spec;\n+\tconst struct rte_flow_item_eth *mask = item->mask;\n+\tstruct igc_ethertype_filter *ether;\n+\n+\tif (mask == NULL) {\n+\t\t/* only n-tuple and SYN filter match the pattern */\n+\t\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE |\n+\t\t\t\tIGC_FILTER_MASK_TCP_SYN);\n+\t\treturn 0;\n+\t}\n+\n+\t/* only ether-type filter match the pattern*/\n+\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_ETHER);\n+\n+\t/* destination and source MAC address are not supported */\n+\tif (!rte_is_zero_ether_addr(&mask->src) ||\n+\t\t!rte_is_zero_ether_addr(&mask->dst))\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\t\"Only support ether-type\");\n+\n+\t/* ether-type mask bits must be all 1 */\n+\tif (IGC_NOT_ALL_BITS_SET(mask->type))\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\t\"Ethernet type mask bits must be all 1\");\n+\n+\tether = &filter->ethertype;\n+\n+\t/* get ether-type */\n+\tether->ether_type = rte_be_to_cpu_16(spec->type);\n+\n+\t/* ether-type should not be IPv4 and IPv6 */\n+\tif (ether->ether_type == RTE_ETHER_TYPE_IPV4 ||\n+\t\tether->ether_type == RTE_ETHER_TYPE_IPV6 ||\n+\t\tether->ether_type == 0)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, NULL,\n+\t\t\t\"IPv4/IPv6/0 not supported by ethertype filter\");\n+\treturn 0;\n+}\n+\n+/* Parse pattern type of IP */\n+static int\n+igc_parse_pattern_ip(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_ipv4 *spec = item->spec;\n+\tconst struct rte_flow_item_ipv4 *mask = item->mask;\n+\n+\tif (mask == NULL) {\n+\t\t/* only n-tuple and SYN filter match this pattern */\n+\t\tIGC_SET_FILTER_MASK(filter,\n+\t\t\tIGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);\n+\t\treturn 0;\n+\t}\n+\n+\t/* only n-tuple filter match this pattern */\n+\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);\n+\n+\t/* only protocol is used */\n+\tif (mask->hdr.version_ihl ||\n+\t\tmask->hdr.type_of_service ||\n+\t\tmask->hdr.total_length ||\n+\t\tmask->hdr.packet_id ||\n+\t\tmask->hdr.fragment_offset ||\n+\t\tmask->hdr.time_to_live ||\n+\t\tmask->hdr.hdr_checksum ||\n+\t\tmask->hdr.dst_addr ||\n+\t\tmask->hdr.src_addr)\n+\t\treturn rte_flow_error_set(error,\n+\t\t\tEINVAL, RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\"IPv4 only support protocol\");\n+\n+\tif (mask->hdr.next_proto_id == 0)\n+\t\treturn 0;\n+\n+\tif (IGC_NOT_ALL_BITS_SET(mask->hdr.next_proto_id))\n+\t\treturn rte_flow_error_set(error,\n+\t\t\t\tEINVAL, RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\t\"IPv4 protocol mask bits must be all 0 or 1\");\n+\n+\t/* get protocol type */\n+\tfilter->ntuple.tuple_info.proto_mask = 1;\n+\tfilter->ntuple.tuple_info.proto = spec->hdr.next_proto_id;\n+\treturn 0;\n+}\n+\n+/*\n+ * Check ipv6 address is 0\n+ * Return 1 if true, 0 for false.\n+ */\n+static inline bool\n+igc_is_zero_ipv6_addr(const void *ipv6_addr)\n+{\n+\tconst uint64_t *ddw = ipv6_addr;\n+\treturn ddw[0] == 0 && ddw[1] == 0;\n+}\n+\n+/* Parse pattern type of IPv6 */\n+static int\n+igc_parse_pattern_ipv6(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_ipv6 *spec = item->spec;\n+\tconst struct rte_flow_item_ipv6 *mask = item->mask;\n+\n+\tif (mask == NULL) {\n+\t\t/* only n-tuple and syn filter match this pattern */\n+\t\tIGC_SET_FILTER_MASK(filter,\n+\t\t\tIGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);\n+\t\treturn 0;\n+\t}\n+\n+\t/* only n-tuple filter match this pattern */\n+\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);\n+\n+\t/* only protocol is used */\n+\tif (mask->hdr.vtc_flow ||\n+\t\tmask->hdr.payload_len ||\n+\t\tmask->hdr.hop_limits ||\n+\t\t!igc_is_zero_ipv6_addr(mask->hdr.src_addr) ||\n+\t\t!igc_is_zero_ipv6_addr(mask->hdr.dst_addr))\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"IPv6 only support protocol\");\n+\n+\tif (mask->hdr.proto == 0)\n+\t\treturn 0;\n+\n+\tif (IGC_NOT_ALL_BITS_SET(mask->hdr.proto))\n+\t\treturn rte_flow_error_set(error,\n+\t\t\t\tEINVAL, RTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\t\"IPv6 protocol mask bits must be all 0 or 1\");\n+\n+\t/* get protocol type */\n+\tfilter->ntuple.tuple_info.proto_mask = 1;\n+\tfilter->ntuple.tuple_info.proto = spec->hdr.proto;\n+\n+\treturn 0;\n+}\n+\n+/* Parse pattern type of UDP */\n+static int\n+igc_parse_pattern_udp(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_udp *spec = item->spec;\n+\tconst struct rte_flow_item_udp *mask = item->mask;\n+\n+\t/* only n-tuple filter match this pattern */\n+\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);\n+\n+\tif (mask == NULL)\n+\t\treturn 0;\n+\n+\t/* only destination port is used */\n+\tif (mask->hdr.dgram_len || mask->hdr.dgram_cksum || mask->hdr.src_port)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\"UDP only support destination port\");\n+\n+\tif (mask->hdr.dst_port == 0)\n+\t\treturn 0;\n+\n+\tif (IGC_NOT_ALL_BITS_SET(mask->hdr.dst_port))\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\t\"UDP port mask bits must be all 0 or 1\");\n+\n+\t/* get destination port info. */\n+\tfilter->ntuple.tuple_info.dst_port_mask = 1;\n+\tfilter->ntuple.tuple_info.dst_port = spec->hdr.dst_port;\n+\n+\treturn 0;\n+}\n+\n+/* Parse pattern type of TCP */\n+static int\n+igc_parse_pattern_tcp(const struct rte_flow_item *item,\n+\t\tstruct igc_all_filter *filter,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_tcp *spec = item->spec;\n+\tconst struct rte_flow_item_tcp *mask = item->mask;\n+\tstruct igc_ntuple_info *tuple_info = &filter->ntuple.tuple_info;\n+\n+\tif (mask == NULL) {\n+\t\t/* only n-tuple filter match this pattern */\n+\t\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);\n+\t\treturn 0;\n+\t}\n+\n+\t/* only n-tuple and SYN filter match this pattern */\n+\tIGC_SET_FILTER_MASK(filter,\n+\t\t\tIGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);\n+\n+\t/* only destination port and TCP flags are used */\n+\tif (mask->hdr.sent_seq ||\n+\t\tmask->hdr.recv_ack ||\n+\t\tmask->hdr.data_off ||\n+\t\tmask->hdr.rx_win ||\n+\t\tmask->hdr.cksum ||\n+\t\tmask->hdr.tcp_urp ||\n+\t\tmask->hdr.src_port)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\"TCP only support destination port and flags\");\n+\n+\t/* if destination port is used */\n+\tif (mask->hdr.dst_port) {\n+\t\t/* only n-tuple match this pattern */\n+\t\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);\n+\n+\t\tif (IGC_NOT_ALL_BITS_SET(mask->hdr.dst_port))\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\t\"TCP port mask bits must be all 1\");\n+\n+\t\t/* get destination port info. */\n+\t\ttuple_info->dst_port = spec->hdr.dst_port;\n+\t\ttuple_info->dst_port_mask = 1;\n+\t}\n+\n+\t/* if TCP flags are used */\n+\tif (mask->hdr.tcp_flags) {\n+\t\tif (IGC_IS_ALL_BITS_SET(mask->hdr.tcp_flags)) {\n+\t\t\t/* only n-tuple match this pattern */\n+\t\t\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);\n+\n+\t\t\t/* get TCP flags */\n+\t\t\ttuple_info->tcp_flags = spec->hdr.tcp_flags;\n+\t\t} else if (mask->hdr.tcp_flags == RTE_TCP_SYN_FLAG) {\n+\t\t\t/* only TCP SYN filter match this pattern */\n+\t\t\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_TCP_SYN);\n+\t\t} else {\n+\t\t\t/* no filter match this pattern */\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_MASK, item,\n+\t\t\t\t\t\"TCP flags can't match\");\n+\t\t}\n+\t} else {\n+\t\t/* only n-tuple match this pattern */\n+\t\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_NTUPLE);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+igc_parse_action_queue(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_action *act,\n+\t\tstruct igc_all_filter *filter,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tuint16_t queue_idx;\n+\n+\tif (act->conf == NULL)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_CONF, act,\n+\t\t\t\t\"NULL pointer\");\n+\n+\t/* only ether-type, n-tuple, SYN filter match the action */\n+\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_ETHER |\n+\t\t\tIGC_FILTER_MASK_NTUPLE | IGC_FILTER_MASK_TCP_SYN);\n+\n+\t/* get queue index */\n+\tqueue_idx = ((const struct rte_flow_action_queue *)act->conf)->index;\n+\n+\t/* check the queue index is valid */\n+\tif (queue_idx >= dev->data->nb_rx_queues)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_CONF, act,\n+\t\t\t\t\"Queue id is invalid\");\n+\n+\t/* get queue info. */\n+\tfilter->ethertype.queue = queue_idx;\n+\tfilter->ntuple.queue = queue_idx;\n+\tfilter->syn.queue = queue_idx;\n+\treturn 0;\n+}\n+\n+/* Parse action of RSS */\n+static int\n+igc_parse_action_rss(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_action *act,\n+\t\tstruct igc_all_filter *filter,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_action_rss *rss = act->conf;\n+\tuint32_t i;\n+\n+\tif (act->conf == NULL)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_CONF, act,\n+\t\t\t\t\"NULL pointer\");\n+\n+\t/* only RSS match the action */\n+\tIGC_SET_FILTER_MASK(filter, IGC_FILTER_MASK_RSS);\n+\n+\t/* RSS redirect table can't be zero and can't exceed 128 */\n+\tif (!rss || !rss->queue_num || rss->queue_num > IGC_RSS_RDT_SIZD)\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_CONF, act,\n+\t\t\t\t\"No valid queues\");\n+\n+\t/* queue index can't exceed max queue index */\n+\tfor (i = 0; i < rss->queue_num; i++) {\n+\t\tif (rss->queue[i] >= dev->data->nb_rx_queues)\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_CONF, act,\n+\t\t\t\t\t\"Queue id is invalid\");\n+\t}\n+\n+\t/* only default RSS hash function is supported */\n+\tif (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_CONF, act,\n+\t\t\t\t\"Only default RSS hash functions is supported\");\n+\n+\tif (rss->level)\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_CONF, act,\n+\t\t\t\t\"Only 0 RSS encapsulation level is supported\");\n+\n+\t/* check key length is valid */\n+\tif (rss->key_len && rss->key_len != sizeof(filter->rss.key))\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION_CONF, act,\n+\t\t\t\t\"RSS hash key must be exactly 40 bytes\");\n+\n+\t/* get RSS info. */\n+\tigc_rss_conf_set(&filter->rss, rss);\n+\treturn 0;\n+}\n+\n+/**\n+ * Allocate a rte_flow from the heap\n+ * Return the pointer of the flow, or NULL for failed\n+ **/\n+static inline struct rte_flow *\n+igc_alloc_flow(const void *filter, enum igc_filter_type type, uint inbytes)\n+{\n+\t/* allocate memory, 8 bytes boundary aligned */\n+\tstruct rte_flow *flow = rte_malloc(\"igc flow filter\",\n+\t\t\tsizeof(struct rte_flow) + inbytes, 8);\n+\tif (flow == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"failed to allocate memory\");\n+\t\treturn NULL;\n+\t}\n+\n+\tflow->filter_type = type;\n+\n+\t/* copy filter data */\n+\tmemcpy(flow->filter, filter, inbytes);\n+\treturn flow;\n+}\n+\n+/* Append a rte_flow to the list */\n+static inline void\n+igc_append_flow(struct igc_flow_list *list, struct rte_flow *flow)\n+{\n+\tTAILQ_INSERT_TAIL(list, flow, node);\n+}\n+\n+/**\n+ * Remove the flow and free the flow buffer\n+ * The caller should make sure the flow is really exist in the list\n+ **/\n+static inline void\n+igc_remove_flow(struct igc_flow_list *list, struct rte_flow *flow)\n+{\n+\tTAILQ_REMOVE(list, flow, node);\n+\trte_free(flow);\n+}\n+\n+/* Check whether the flow is really in the list or not */\n+static inline bool\n+igc_is_flow_in_list(struct igc_flow_list *list, struct rte_flow *flow)\n+{\n+\tstruct rte_flow *it;\n+\n+\tTAILQ_FOREACH(it, list, node) {\n+\t\tif (it == flow)\n+\t\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n+/**\n+ * Create a flow rule.\n+ * Theoretically one rule can match more than one filters.\n+ * We will let it use the filter which it hit first.\n+ * So, the sequence matters.\n+ **/\n+static struct rte_flow *\n+igc_flow_create(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_attr *attr,\n+\t\tconst struct rte_flow_item patterns[],\n+\t\tconst struct rte_flow_action actions[],\n+\t\tstruct rte_flow_error *error)\n+{\n+\tstruct rte_flow *flow = NULL;\n+\tstruct igc_all_filter filter;\n+\tint ret;\n+\n+\tret = igc_parse_flow(dev, attr, patterns, actions, error, &filter);\n+\tif (ret)\n+\t\treturn NULL;\n+\tret = -ENOMEM;\n+\n+\tswitch (filter.mask) {\n+\tcase IGC_FILTER_MASK_ETHER:\n+\t\tflow = igc_alloc_flow(&filter.ethertype,\n+\t\t\t\tIGC_FILTER_TYPE_ETHERTYPE,\n+\t\t\t\tsizeof(filter.ethertype));\n+\t\tif (flow)\n+\t\t\tret = igc_add_ethertype_filter(dev, &filter.ethertype);\n+\t\tbreak;\n+\tcase IGC_FILTER_MASK_NTUPLE:\n+\t\t/* Check n-tuple filter is valid */\n+\t\tif (filter.ntuple.tuple_info.dst_port_mask == 0 &&\n+\t\t\tfilter.ntuple.tuple_info.proto_mask == 0) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_NONE, NULL,\n+\t\t\t\t\t\"Flow can't be recognized\");\n+\t\t\treturn NULL;\n+\t\t}\n+\n+\t\tflow = igc_alloc_flow(&filter.ntuple, IGC_FILTER_TYPE_NTUPLE,\n+\t\t\t\tsizeof(filter.ntuple));\n+\t\tif (flow)\n+\t\t\tret = igc_add_ntuple_filter(dev, &filter.ntuple);\n+\t\tbreak;\n+\tcase IGC_FILTER_MASK_TCP_SYN:\n+\t\tflow = igc_alloc_flow(&filter.syn, IGC_FILTER_TYPE_SYN,\n+\t\t\t\tsizeof(filter.syn));\n+\t\tif (flow)\n+\t\t\tret = igc_set_syn_filter(dev, &filter.syn);\n+\t\tbreak;\n+\tcase IGC_FILTER_MASK_RSS:\n+\t\tflow = igc_alloc_flow(&filter.rss, IGC_FILTER_TYPE_HASH,\n+\t\t\t\tsizeof(filter.rss));\n+\t\tif (flow) {\n+\t\t\tstruct igc_rss_filter *rss =\n+\t\t\t\t\t(struct igc_rss_filter *)flow->filter;\n+\t\t\trss->conf.key = rss->key;\n+\t\t\trss->conf.queue = rss->queue;\n+\t\t\tret = igc_add_rss_filter(dev, &filter.rss);\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_NONE, NULL,\n+\t\t\t\t\"Flow can't be recognized\");\n+\t\treturn NULL;\n+\t}\n+\n+\tif (ret) {\n+\t\t/* check and free the memory */\n+\t\tif (flow)\n+\t\t\trte_free(flow);\n+\n+\t\trte_flow_error_set(error, -ret,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t\"Failed to create flow.\");\n+\t\treturn NULL;\n+\t}\n+\n+\t/* append the flow to the tail of the list */\n+\tigc_append_flow(IGC_DEV_PRIVATE_FLOW_LIST(dev), flow);\n+\treturn flow;\n+}\n+\n+/**\n+ * Check if the flow rule is supported by the device.\n+ * It only checks the format. Don't guarantee the rule can be programmed into\n+ * the HW. Because there can be no enough room for the rule.\n+ **/\n+static int\n+igc_flow_validate(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_attr *attr,\n+\t\tconst struct rte_flow_item patterns[],\n+\t\tconst struct rte_flow_action actions[],\n+\t\tstruct rte_flow_error *error)\n+{\n+\tstruct igc_all_filter filter;\n+\tint ret;\n+\n+\tret = igc_parse_flow(dev, attr, patterns, actions, error, &filter);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tswitch (filter.mask) {\n+\tcase IGC_FILTER_MASK_NTUPLE:\n+\t\t/* Check n-tuple filter is valid */\n+\t\tif (filter.ntuple.tuple_info.dst_port_mask == 0 &&\n+\t\t\tfilter.ntuple.tuple_info.proto_mask == 0)\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_NONE, NULL,\n+\t\t\t\t\t\"Flow can't be recognized\");\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Disable a valid flow, the flow must be not NULL and\n+ * chained in the device flow list.\n+ **/\n+static int\n+igc_disable_flow(struct rte_eth_dev *dev, struct rte_flow *flow)\n+{\n+\tint ret = 0;\n+\n+\tswitch (flow->filter_type) {\n+\tcase IGC_FILTER_TYPE_ETHERTYPE:\n+\t\tret = igc_del_ethertype_filter(dev,\n+\t\t\t(struct igc_ethertype_filter *)&flow->filter);\n+\t\tbreak;\n+\tcase IGC_FILTER_TYPE_NTUPLE:\n+\t\tret = igc_del_ntuple_filter(dev,\n+\t\t\t\t(struct igc_ntuple_filter *)&flow->filter);\n+\t\tbreak;\n+\tcase IGC_FILTER_TYPE_SYN:\n+\t\tigc_clear_syn_filter(dev);\n+\t\tbreak;\n+\tcase IGC_FILTER_TYPE_HASH:\n+\t\tret = igc_del_rss_filter(dev);\n+\t\tbreak;\n+\tdefault:\n+\t\tPMD_DRV_LOG(ERR, \"Filter type (%d) not supported\",\n+\t\t\t\tflow->filter_type);\n+\t\tret = -EINVAL;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+/* Destroy a flow rule */\n+static int\n+igc_flow_destroy(struct rte_eth_dev *dev,\n+\t\tstruct rte_flow *flow,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tstruct igc_flow_list *list = IGC_DEV_PRIVATE_FLOW_LIST(dev);\n+\tint ret;\n+\n+\tif (!flow) {\n+\t\tPMD_DRV_LOG(ERR, \"NULL flow!\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* check the flow is create by IGC PMD */\n+\tif (!igc_is_flow_in_list(list, flow)) {\n+\t\tPMD_DRV_LOG(ERR, \"Flow(%p) not been found!\", flow);\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tret = igc_disable_flow(dev, flow);\n+\tif (ret)\n+\t\trte_flow_error_set(error, -ret,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_HANDLE,\n+\t\t\t\tNULL, \"Failed to destroy flow\");\n+\n+\tigc_remove_flow(list, flow);\n+\treturn ret;\n+}\n+\n+/* Initiate device flow list header */\n+void\n+igc_flow_init(struct rte_eth_dev *dev)\n+{\n+\tTAILQ_INIT(IGC_DEV_PRIVATE_FLOW_LIST(dev));\n+}\n+\n+/* Destroy all flow in the list and free memory */\n+int\n+igc_flow_flush(struct rte_eth_dev *dev,\n+\t\t__rte_unused struct rte_flow_error *error)\n+{\n+\tstruct igc_flow_list *list = IGC_DEV_PRIVATE_FLOW_LIST(dev);\n+\tstruct rte_flow *flow;\n+\n+\twhile ((flow = TAILQ_FIRST(list)) != NULL) {\n+\t\tigc_disable_flow(dev, flow);\n+\t\tigc_remove_flow(list, flow);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+const struct rte_flow_ops igc_flow_ops = {\n+\t.validate = igc_flow_validate,\n+\t.create = igc_flow_create,\n+\t.destroy = igc_flow_destroy,\n+\t.flush = igc_flow_flush,\n+};\ndiff --git a/drivers/net/igc/igc_flow.h b/drivers/net/igc/igc_flow.h\nnew file mode 100644\nindex 0000000..310b4bd\n--- /dev/null\n+++ b/drivers/net/igc/igc_flow.h\n@@ -0,0 +1,25 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2020 Intel Corporation\n+ */\n+\n+#ifndef _IGC_FLOW_H_\n+#define _IGC_FLOW_H_\n+\n+#include <rte_flow_driver.h>\n+#include \"igc_ethdev.h\"\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+extern const struct rte_flow_ops igc_flow_ops;\n+\n+void igc_flow_init(struct rte_eth_dev *dev);\n+int igc_flow_flush(struct rte_eth_dev *dev,\n+\t\t__rte_unused struct rte_flow_error *error);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* _IGC_FLOW_H_ */\ndiff --git a/drivers/net/igc/igc_txrx.c b/drivers/net/igc/igc_txrx.c\nindex ceb5537..0914af0 100644\n--- a/drivers/net/igc/igc_txrx.c\n+++ b/drivers/net/igc/igc_txrx.c\n@@ -834,7 +834,7 @@ int eth_igc_rx_descriptor_status(void *rx_queue, uint16_t offset)\n \t0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA,\n };\n \n-static void\n+void\n igc_rss_disable(struct rte_eth_dev *dev)\n {\n \tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n@@ -915,6 +915,136 @@ int eth_igc_rx_descriptor_status(void *rx_queue, uint16_t offset)\n \tigc_hw_rss_hash_set(hw, &rss_conf);\n }\n \n+int\n+igc_del_rss_filter(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_rss_filter *rss_filter = IGC_DEV_PRIVATE_RSS_FILTER(dev);\n+\n+\tif (rss_filter->enable) {\n+\t\t/* recover default RSS configuration */\n+\t\tigc_rss_configure(dev);\n+\n+\t\t/* disable RSS logic and clear filter data */\n+\t\tigc_rss_disable(dev);\n+\t\tmemset(rss_filter, 0, sizeof(*rss_filter));\n+\t\treturn 0;\n+\t}\n+\tPMD_DRV_LOG(ERR, \"filter not exist!\");\n+\treturn -ENOENT;\n+}\n+\n+/* Initiate the filter structure by the structure of rte_flow_action_rss */\n+void\n+igc_rss_conf_set(struct igc_rss_filter *out,\n+\t\tconst struct rte_flow_action_rss *rss)\n+{\n+\tout->conf.func = rss->func;\n+\tout->conf.level = rss->level;\n+\tout->conf.types = rss->types;\n+\n+\tif (rss->key_len == sizeof(out->key)) {\n+\t\tmemcpy(out->key, rss->key, rss->key_len);\n+\t\tout->conf.key = out->key;\n+\t\tout->conf.key_len = rss->key_len;\n+\t} else {\n+\t\tout->conf.key = NULL;\n+\t\tout->conf.key_len = 0;\n+\t}\n+\n+\tif (rss->queue_num <= IGC_RSS_RDT_SIZD) {\n+\t\tmemcpy(out->queue, rss->queue,\n+\t\t\tsizeof(*out->queue) * rss->queue_num);\n+\t\tout->conf.queue = out->queue;\n+\t\tout->conf.queue_num = rss->queue_num;\n+\t} else {\n+\t\tout->conf.queue = NULL;\n+\t\tout->conf.queue_num = 0;\n+\t}\n+}\n+\n+int\n+igc_add_rss_filter(struct rte_eth_dev *dev, struct igc_rss_filter *rss)\n+{\n+\tstruct rte_eth_rss_conf rss_conf = {\n+\t\t.rss_key = rss->conf.key_len ?\n+\t\t\t(void *)(uintptr_t)rss->conf.key : NULL,\n+\t\t.rss_key_len = rss->conf.key_len,\n+\t\t.rss_hf = rss->conf.types,\n+\t};\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct igc_rss_filter *rss_filter = IGC_DEV_PRIVATE_RSS_FILTER(dev);\n+\tuint32_t i, j;\n+\n+\t/* check RSS type is valid */\n+\tif ((rss_conf.rss_hf & IGC_RSS_OFFLOAD_ALL) == 0) {\n+\t\tPMD_DRV_LOG(ERR, \"RSS type(0x%\" PRIx64 \") error!, only 0x%\"\n+\t\t\t\tPRIx64 \" been supported\", rss_conf.rss_hf,\n+\t\t\t\t(uint64_t)IGC_RSS_OFFLOAD_ALL);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* check queue count is not zero */\n+\tif (!rss->conf.queue_num) {\n+\t\tPMD_DRV_LOG(ERR, \"Queue number should not be 0!\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* check queue id is valid */\n+\tfor (i = 0; i < rss->conf.queue_num; i++)\n+\t\tif (rss->conf.queue[i] >= dev->data->nb_rx_queues) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Queue id %u is invalid!\",\n+\t\t\t\t\trss->conf.queue[i]);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t/* only support one filter */\n+\tif (rss_filter->enable) {\n+\t\tPMD_DRV_LOG(ERR, \"Only support one RSS filter!\");\n+\t\treturn -ENOTSUP;\n+\t}\n+\trss_filter->enable = 1;\n+\n+\tigc_rss_conf_set(rss_filter, &rss->conf);\n+\n+\t/* Fill in redirection table. */\n+\tfor (i = 0, j = 0; i < IGC_RSS_RDT_SIZD; i++, j++) {\n+\t\tunion igc_rss_reta_reg reta;\n+\t\tuint16_t q_idx, reta_idx;\n+\n+\t\tif (j == rss->conf.queue_num)\n+\t\t\tj = 0;\n+\t\tq_idx = rss->conf.queue[j];\n+\t\treta_idx = i % sizeof(reta);\n+\t\treta.bytes[reta_idx] = q_idx;\n+\t\tif (reta_idx == sizeof(reta) - 1)\n+\t\t\tIGC_WRITE_REG_LE_VALUE(hw,\n+\t\t\t\tIGC_RETA(i / sizeof(reta)), reta.dword);\n+\t}\n+\n+\tif (rss_conf.rss_key == NULL)\n+\t\trss_conf.rss_key = default_rss_key;\n+\tigc_hw_rss_hash_set(hw, &rss_conf);\n+\treturn 0;\n+}\n+\n+void\n+igc_clear_rss_filter(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_rss_filter *rss_filter = IGC_DEV_PRIVATE_RSS_FILTER(dev);\n+\n+\tif (!rss_filter->enable) {\n+\t\tPMD_DRV_LOG(WARNING, \"RSS filter not enabled!\");\n+\t\treturn;\n+\t}\n+\n+\t/* recover default RSS configuration */\n+\tigc_rss_configure(dev);\n+\n+\t/* disable RSS logic and clear filter data */\n+\tigc_rss_disable(dev);\n+\tmemset(rss_filter, 0, sizeof(*rss_filter));\n+}\n+\n static int\n igc_dev_mq_rx_configure(struct rte_eth_dev *dev)\n {\ndiff --git a/drivers/net/igc/igc_txrx.h b/drivers/net/igc/igc_txrx.h\nindex 0cf9cbe..68e4508 100644\n--- a/drivers/net/igc/igc_txrx.h\n+++ b/drivers/net/igc/igc_txrx.h\n@@ -38,8 +38,14 @@ int eth_igc_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,\n \n int igc_rx_init(struct rte_eth_dev *dev);\n void igc_tx_init(struct rte_eth_dev *dev);\n+void igc_rss_disable(struct rte_eth_dev *dev);\n void\n igc_hw_rss_hash_set(struct igc_hw *hw, struct rte_eth_rss_conf *rss_conf);\n+int igc_del_rss_filter(struct rte_eth_dev *dev);\n+void igc_rss_conf_set(struct igc_rss_filter *out,\n+\t\tconst struct rte_flow_action_rss *rss);\n+int igc_add_rss_filter(struct rte_eth_dev *dev, struct igc_rss_filter *rss);\n+void igc_clear_rss_filter(struct rte_eth_dev *dev);\n void eth_igc_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,\n \tstruct rte_eth_rxq_info *qinfo);\n void eth_igc_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,\ndiff --git a/drivers/net/igc/meson.build b/drivers/net/igc/meson.build\nindex e402f26..fba119c 100644\n--- a/drivers/net/igc/meson.build\n+++ b/drivers/net/igc/meson.build\n@@ -7,7 +7,9 @@ objs = [base_objs]\n sources = files(\n \t'igc_logs.c',\n \t'igc_ethdev.c',\n-\t'igc_txrx.c'\n+\t'igc_txrx.c',\n+\t'igc_filter.c',\n+\t'igc_flow.c'\n )\n \n includes += include_directories('base')\n",
    "prefixes": [
        "v3",
        "11/11"
    ]
}