get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 131040,
    "url": "https://patches.dpdk.org/api/patches/131040/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20230901032842.223547-32-wanry@3snic.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": "<20230901032842.223547-32-wanry@3snic.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230901032842.223547-32-wanry@3snic.com",
    "date": "2023-09-01T03:28:41",
    "name": "[v3,31/32] net/sssnic: add generic flow ops",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "df2becf44742c8b8b809162c9ea2645336c024a7",
    "submitter": {
        "id": 3119,
        "url": "https://patches.dpdk.org/api/people/3119/?format=api",
        "name": "Renyong Wan",
        "email": "wanry@3snic.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/20230901032842.223547-32-wanry@3snic.com/mbox/",
    "series": [
        {
            "id": 29399,
            "url": "https://patches.dpdk.org/api/series/29399/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=29399",
            "date": "2023-09-01T03:28:13",
            "name": "Introduce sssnic PMD for 3SNIC's 9x0 serials Ethernet adapters",
            "version": 3,
            "mbox": "https://patches.dpdk.org/series/29399/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/131040/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/131040/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 mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 55A8142219;\n\tFri,  1 Sep 2023 05:32:29 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 88E4940ED9;\n\tFri,  1 Sep 2023 05:29:57 +0200 (CEST)",
            "from VLXDG1SPAM1.ramaxel.com (email.ramaxel.com [221.4.138.186])\n by mails.dpdk.org (Postfix) with ESMTP id 32CCB402DA\n for <dev@dpdk.org>; Fri,  1 Sep 2023 05:29:51 +0200 (CEST)",
            "from V12DG1MBS03.ramaxel.local ([172.26.18.33])\n by VLXDG1SPAM1.ramaxel.com with ESMTP id 3813T4Ii033406;\n Fri, 1 Sep 2023 11:29:05 +0800 (GMT-8)\n (envelope-from wanry@3snic.com)",
            "from localhost.localdomain (10.64.136.151) by\n V12DG1MBS03.ramaxel.local (172.26.18.33) with Microsoft SMTP Server\n (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id\n 15.1.2375.17; Fri, 1 Sep 2023 11:29:03 +0800"
        ],
        "From": "<wanry@3snic.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<ferruh.yigit@amd.com>, Renyong Wan <wanry@3snic.com>, Steven Song\n <steven.song@3snic.com>",
        "Subject": "[PATCH v3 31/32] net/sssnic: add generic flow ops",
        "Date": "Fri, 1 Sep 2023 11:28:41 +0800",
        "Message-ID": "<20230901032842.223547-32-wanry@3snic.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20230901032842.223547-1-wanry@3snic.com>",
        "References": "<20230901032842.223547-1-wanry@3snic.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "7bit",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.64.136.151]",
        "X-ClientProxiedBy": "V12DG1MBS03.ramaxel.local (172.26.18.33) To\n V12DG1MBS03.ramaxel.local (172.26.18.33)",
        "X-DNSRBL": "",
        "X-SPAM-SOURCE-CHECK": "pass",
        "X-MAIL": "VLXDG1SPAM1.ramaxel.com 3813T4Ii033406",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "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"
    },
    "content": "From: Renyong Wan <wanry@3snic.com>\n\nSigned-off-by: Steven Song <steven.song@3snic.com>\nSigned-off-by: Renyong Wan <wanry@3snic.com>\n---\nv2:\n* Fixed 'mask->hdr.src_addr' will always evaluate to 'true'.\n* Removed error.h from including files.\n---\n doc/guides/nics/features/sssnic.ini     |   12 +\n drivers/net/sssnic/base/sssnic_api.c    |  264 ++++++\n drivers/net/sssnic/base/sssnic_api.h    |   22 +\n drivers/net/sssnic/base/sssnic_cmd.h    |   71 ++\n drivers/net/sssnic/base/sssnic_hw.h     |    3 +\n drivers/net/sssnic/base/sssnic_misc.h   |    7 +\n drivers/net/sssnic/meson.build          |    2 +\n drivers/net/sssnic/sssnic_ethdev.c      |   12 +\n drivers/net/sssnic/sssnic_ethdev.h      |    1 +\n drivers/net/sssnic/sssnic_ethdev_fdir.c | 1017 +++++++++++++++++++++++\n drivers/net/sssnic/sssnic_ethdev_fdir.h |  332 ++++++++\n drivers/net/sssnic/sssnic_ethdev_flow.c |  981 ++++++++++++++++++++++\n drivers/net/sssnic/sssnic_ethdev_flow.h |   11 +\n drivers/net/sssnic/sssnic_ethdev_rx.c   |   18 +\n 14 files changed, 2753 insertions(+)\n create mode 100644 drivers/net/sssnic/sssnic_ethdev_fdir.c\n create mode 100644 drivers/net/sssnic/sssnic_ethdev_fdir.h\n create mode 100644 drivers/net/sssnic/sssnic_ethdev_flow.c\n create mode 100644 drivers/net/sssnic/sssnic_ethdev_flow.h",
    "diff": "diff --git a/doc/guides/nics/features/sssnic.ini b/doc/guides/nics/features/sssnic.ini\nindex f5738ac934..57e7440d86 100644\n--- a/doc/guides/nics/features/sssnic.ini\n+++ b/doc/guides/nics/features/sssnic.ini\n@@ -33,3 +33,15 @@ FW version           = Y\n Linux                = Y\n ARMv8                = Y\n x86-64               = Y\n+\n+[rte_flow items]\n+any                  = Y\n+eth                  = Y\n+ipv4                 = Y\n+ipv6                 = Y\n+tcp                  = Y\n+udp                  = Y\n+vxlan                = Y\n+\n+[rte_flow actions]\n+queue                = Y\ndiff --git a/drivers/net/sssnic/base/sssnic_api.c b/drivers/net/sssnic/base/sssnic_api.c\nindex 68c16c9c1e..0e965442fd 100644\n--- a/drivers/net/sssnic/base/sssnic_api.c\n+++ b/drivers/net/sssnic/base/sssnic_api.c\n@@ -1635,3 +1635,267 @@ sssnic_vlan_filter_set(struct sssnic_hw *hw, uint16_t vid, bool add)\n \n \treturn 0;\n }\n+\n+int\n+sssnic_tcam_enable_set(struct sssnic_hw *hw, bool enabled)\n+{\n+\tstruct sssnic_tcam_enable_set_cmd cmd;\n+\tstruct sssnic_msg msg;\n+\tuint32_t cmd_len;\n+\tint ret;\n+\n+\tmemset(&cmd, 0, sizeof(cmd));\n+\tcmd_len = sizeof(cmd);\n+\tcmd.function = SSSNIC_FUNC_IDX(hw);\n+\tcmd.enabled = enabled ? 1 : 0;\n+\n+\tsssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len,\n+\t\tSSSNIC_SET_TCAM_ENABLE_CMD, SSSNIC_MPU_FUNC_IDX,\n+\t\tSSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ);\n+\tret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to send mbox message, ret=%d\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tif (cmd_len == 0 || cmd.common.status != 0) {\n+\t\tif (cmd.common.status == SSSNIC_TCAM_CMD_STATUS_UNSUPPORTED)\n+\t\t\tPMD_DRV_LOG(WARNING,\n+\t\t\t\t\"SSSNIC_SET_TCAM_ENABLED_CMD is unsupported\");\n+\t\telse\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Bad response to SSSNIC_SET_TCAM_ENABLE_CMD, len=%u, status=%u\",\n+\t\t\t\tcmd_len, cmd.common.status);\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+sssnic_tcam_flush(struct sssnic_hw *hw)\n+{\n+\tstruct sssnic_tcam_flush_cmd cmd;\n+\tstruct sssnic_msg msg;\n+\tuint32_t cmd_len;\n+\tint ret;\n+\n+\tmemset(&cmd, 0, sizeof(cmd));\n+\tcmd_len = sizeof(cmd);\n+\tcmd.function = SSSNIC_FUNC_IDX(hw);\n+\n+\tsssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len, SSSNIC_FLUSH_TCAM_CMD,\n+\t\tSSSNIC_MPU_FUNC_IDX, SSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ);\n+\tret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to send mbox message, ret=%d\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tif (cmd_len == 0 || cmd.common.status != 0) {\n+\t\tif (cmd.common.status == SSSNIC_TCAM_CMD_STATUS_UNSUPPORTED)\n+\t\t\tPMD_DRV_LOG(WARNING,\n+\t\t\t\t\"SSSNIC_FLUSH_TCAM_CMD is unsupported\");\n+\t\telse\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Bad response to SSSNIC_FLUSH_TCAM_CMD, len=%u, status=%u\",\n+\t\t\t\tcmd_len, cmd.common.status);\n+\t\treturn -EIO;\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+sssnic_tcam_disable_and_flush(struct sssnic_hw *hw)\n+{\n+\tint ret;\n+\n+\tret = sssnic_tcam_enable_set(hw, 0);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Could not disable TCAM\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = sssnic_tcam_flush(hw);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Could not flush TCAM\");\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_tcam_block_cfg(struct sssnic_hw *hw, uint8_t flag, uint16_t *block_idx)\n+{\n+\tstruct sssnic_tcam_block_cfg_cmd cmd;\n+\tstruct sssnic_msg msg;\n+\tuint32_t cmd_len;\n+\tint ret;\n+\n+\tmemset(&cmd, 0, sizeof(cmd));\n+\tcmd_len = sizeof(cmd);\n+\tcmd.function = SSSNIC_FUNC_IDX(hw);\n+\tcmd.flag = flag;\n+\tif (flag == SSSNIC_TCAM_BLOCK_CFG_CMD_FLAG_FREE)\n+\t\tcmd.idx = *block_idx;\n+\n+\tsssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len,\n+\t\tSSSNIC_TCAM_CFG_BLOCK_CMD, SSSNIC_MPU_FUNC_IDX,\n+\t\tSSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ);\n+\tret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to send mbox message, ret=%d\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tif (cmd_len == 0 || cmd.common.status != 0) {\n+\t\tif (cmd.common.status == SSSNIC_TCAM_CMD_STATUS_UNSUPPORTED)\n+\t\t\tPMD_DRV_LOG(WARNING,\n+\t\t\t\t\"SSSNIC_CFG_TCAM_BLOCK_CMD is unsupported\");\n+\t\telse\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Bad response to SSSNIC_CFG_TCAM_BLOCK_CMD, len=%u, status=%u\",\n+\t\t\t\tcmd_len, cmd.common.status);\n+\t\treturn -EIO;\n+\t}\n+\n+\tif (flag == SSSNIC_TCAM_BLOCK_CFG_CMD_FLAG_ALLOC)\n+\t\t*block_idx = cmd.idx;\n+\n+\treturn 0;\n+}\n+\n+int\n+sssnic_tcam_block_alloc(struct sssnic_hw *hw, uint16_t *block_idx)\n+{\n+\tif (block_idx == NULL)\n+\t\treturn -EINVAL;\n+\n+\treturn sssnic_tcam_block_cfg(hw, SSSNIC_TCAM_BLOCK_CFG_CMD_FLAG_ALLOC,\n+\t\tblock_idx);\n+}\n+\n+int\n+sssnic_tcam_block_free(struct sssnic_hw *hw, uint16_t block_idx)\n+{\n+\treturn sssnic_tcam_block_cfg(hw, SSSNIC_TCAM_BLOCK_CFG_CMD_FLAG_FREE,\n+\t\t&block_idx);\n+}\n+\n+int\n+sssnic_tcam_packet_type_filter_set(struct sssnic_hw *hw, uint8_t ptype,\n+\tuint16_t qid, bool enabled)\n+{\n+\tstruct sssnic_tcam_ptype_filter_set_cmd cmd;\n+\tstruct sssnic_msg msg;\n+\tuint32_t cmd_len;\n+\tint ret;\n+\n+\tmemset(&cmd, 0, sizeof(cmd));\n+\tcmd_len = sizeof(cmd);\n+\tcmd.function = SSSNIC_FUNC_IDX(hw);\n+\tcmd.ptype = ptype;\n+\tcmd.qid = qid;\n+\tcmd.enable = enabled ? 1 : 0;\n+\n+\tsssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len,\n+\t\tSSSNIC_TCAM_SET_PTYPE_FILTER_CMD, SSSNIC_MPU_FUNC_IDX,\n+\t\tSSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ);\n+\tret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to send mbox message, ret=%d\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tif (cmd_len == 0 || cmd.common.status != 0) {\n+\t\tif (cmd.common.status == SSSNIC_TCAM_CMD_STATUS_UNSUPPORTED)\n+\t\t\tPMD_DRV_LOG(WARNING,\n+\t\t\t\t\"SSSNIC_TCAM_SET_PTYPE_FILTER_CMD is unsupported\");\n+\t\telse\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Bad response to SSSNIC_TCAM_SET_PTYPE_FILTER_CMD, len=%u, status=%u\",\n+\t\t\t\tcmd_len, cmd.common.status);\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+sssnic_tcam_entry_add(struct sssnic_hw *hw, struct sssnic_tcam_entry *entry)\n+{\n+\tstruct sssnic_tcam_entry_add_cmd cmd;\n+\tstruct sssnic_msg msg;\n+\tuint32_t cmd_len;\n+\tint ret;\n+\n+\tmemset(&cmd, 0, sizeof(cmd));\n+\tcmd_len = sizeof(cmd);\n+\tcmd.function = SSSNIC_FUNC_IDX(hw);\n+\trte_memcpy(&cmd.data, entry, sizeof(cmd.data));\n+\n+\tif (entry->index >= SSSNIC_TCAM_MAX_ENTRY_NUM) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid TCAM entry index: %u\", entry->index);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len,\n+\t\tSSSNIC_ADD_TCAM_ENTRY_CMD, SSSNIC_MPU_FUNC_IDX,\n+\t\tSSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ);\n+\tret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to send mbox message, ret=%d\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tif (cmd_len == 0 || cmd.common.status != 0) {\n+\t\tif (cmd.common.status == SSSNIC_TCAM_CMD_STATUS_UNSUPPORTED)\n+\t\t\tPMD_DRV_LOG(WARNING,\n+\t\t\t\t\"SSSNIC_ADD_TCAM_ENTRY_CMD is unsupported\");\n+\t\telse\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Bad response to SSSNIC_ADD_TCAM_ENTRY_CMD, len=%u, status=%u\",\n+\t\t\t\tcmd_len, cmd.common.status);\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+sssnic_tcam_entry_del(struct sssnic_hw *hw, uint32_t entry_idx)\n+{\n+\tstruct sssnic_tcam_entry_del_cmd cmd;\n+\tstruct sssnic_msg msg;\n+\tuint32_t cmd_len;\n+\tint ret;\n+\n+\tmemset(&cmd, 0, sizeof(cmd));\n+\tcmd_len = sizeof(cmd);\n+\tcmd.function = SSSNIC_FUNC_IDX(hw);\n+\tcmd.start = entry_idx;\n+\tcmd.num = 1;\n+\n+\tsssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len,\n+\t\tSSSNIC_DEL_TCAM_ENTRY_CMD, SSSNIC_MPU_FUNC_IDX,\n+\t\tSSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ);\n+\tret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to send mbox message, ret=%d\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tif (cmd_len == 0 || cmd.common.status != 0) {\n+\t\tif (cmd.common.status == SSSNIC_TCAM_CMD_STATUS_UNSUPPORTED)\n+\t\t\tPMD_DRV_LOG(WARNING,\n+\t\t\t\t\"SSSNIC_ADD_TCAM_ENTRY_CMD is unsupported\");\n+\t\telse\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Bad response to SSSNIC_ADD_TCAM_ENTRY_CMD, len=%u, status=%u\",\n+\t\t\t\tcmd_len, cmd.common.status);\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/net/sssnic/base/sssnic_api.h b/drivers/net/sssnic/base/sssnic_api.h\nindex 28b235dda2..7a02ec61ee 100644\n--- a/drivers/net/sssnic/base/sssnic_api.h\n+++ b/drivers/net/sssnic/base/sssnic_api.h\n@@ -409,6 +409,18 @@ struct sssnic_fw_version {\n \tchar time[SSSNIC_FW_VERSION_LEN];\n };\n \n+struct sssnic_tcam_entry {\n+\tuint32_t index;\n+\tstruct {\n+\t\tuint32_t qid;\n+\t\tuint32_t resvd;\n+\t} result;\n+\tstruct {\n+\t\tuint8_t data0[SSSNIC_TCAM_KEY_SIZE];\n+\t\tuint8_t data1[SSSNIC_TCAM_KEY_SIZE];\n+\t} key;\n+};\n+\n int sssnic_msix_attr_get(struct sssnic_hw *hw, uint16_t msix_idx,\n \tstruct sssnic_msix_attr *attr);\n int sssnic_msix_attr_set(struct sssnic_hw *hw, uint16_t msix_idx,\n@@ -470,5 +482,15 @@ int sssnic_flow_ctrl_set(struct sssnic_hw *hw, bool autoneg, bool rx_en,\n int sssnic_flow_ctrl_get(struct sssnic_hw *hw, bool *autoneg, bool *rx_en,\n \tbool *tx_en);\n int sssnic_vlan_filter_set(struct sssnic_hw *hw, uint16_t vid, bool add);\n+int sssnic_tcam_enable_set(struct sssnic_hw *hw, bool enabled);\n+int sssnic_tcam_flush(struct sssnic_hw *hw);\n+int sssnic_tcam_disable_and_flush(struct sssnic_hw *hw);\n+int sssnic_tcam_block_alloc(struct sssnic_hw *hw, uint16_t *block_idx);\n+int sssnic_tcam_block_free(struct sssnic_hw *hw, uint16_t block_idx);\n+int sssnic_tcam_packet_type_filter_set(struct sssnic_hw *hw, uint8_t ptype,\n+\tuint16_t qid, bool enabled);\n+int sssnic_tcam_entry_add(struct sssnic_hw *hw,\n+\tstruct sssnic_tcam_entry *entry);\n+int sssnic_tcam_entry_del(struct sssnic_hw *hw, uint32_t entry_idx);\n \n #endif /* _SSSNIC_API_H_ */\ndiff --git a/drivers/net/sssnic/base/sssnic_cmd.h b/drivers/net/sssnic/base/sssnic_cmd.h\nindex 3e70d0e223..c75cb0dad3 100644\n--- a/drivers/net/sssnic/base/sssnic_cmd.h\n+++ b/drivers/net/sssnic/base/sssnic_cmd.h\n@@ -75,6 +75,16 @@ enum sssnic_rss_cmd_id {\n \tSSSNIC_SET_RSS_TYPE_CMD = 65,\n };\n \n+#define SSSNIC_TCAM_CMD_STATUS_UNSUPPORTED 0xff\n+enum sssnic_tcam_cmd_id {\n+\tSSSNIC_ADD_TCAM_ENTRY_CMD = 80,\n+\tSSSNIC_DEL_TCAM_ENTRY_CMD = 81,\n+\tSSSNIC_FLUSH_TCAM_CMD = 83,\n+\tSSSNIC_TCAM_CFG_BLOCK_CMD = 84,\n+\tSSSNIC_SET_TCAM_ENABLE_CMD = 85,\n+\tSSSNIC_TCAM_SET_PTYPE_FILTER_CMD = 91,\n+};\n+\n struct sssnic_cmd_common {\n \tuint8_t status;\n \tuint8_t version;\n@@ -434,4 +444,65 @@ struct sssnic_vlan_filter_set_cmd {\n \tuint16_t resvd1;\n };\n \n+struct sssnic_tcam_enable_set_cmd {\n+\tstruct sssnic_cmd_common common;\n+\tuint16_t function;\n+\tuint8_t enabled;\n+\tuint8_t resvd[5];\n+};\n+\n+struct sssnic_tcam_flush_cmd {\n+\tstruct sssnic_cmd_common common;\n+\tuint16_t function;\n+\tuint16_t resvd;\n+};\n+\n+#define SSSNIC_TCAM_BLOCK_CFG_CMD_FLAG_ALLOC 1\n+#define SSSNIC_TCAM_BLOCK_CFG_CMD_FLAG_FREE 0\n+struct sssnic_tcam_block_cfg_cmd {\n+\tstruct sssnic_cmd_common common;\n+\tuint16_t function;\n+\tuint8_t flag; /* SSSNIC_TCAM_BLOCK_CFG_CMD_FLAG_XX */\n+\tuint8_t type;\n+\tuint16_t idx;\n+\tuint16_t resvd;\n+};\n+\n+struct sssnic_tcam_ptype_filter_set_cmd {\n+\tstruct sssnic_cmd_common common;\n+\tuint16_t function;\n+\tuint16_t resvd0;\n+\tuint8_t enable;\n+\tuint8_t ptype;\n+\tuint8_t qid;\n+\tuint8_t resvd1;\n+};\n+\n+struct sssnic_tcam_entry_add_cmd {\n+\tstruct sssnic_cmd_common common;\n+\tuint16_t function;\n+\tuint8_t type;\n+\tuint8_t resv;\n+\tstruct {\n+\t\tuint32_t index;\n+\t\tstruct {\n+\t\t\tuint32_t qid;\n+\t\t\tuint32_t resvd;\n+\t\t} result;\n+\t\tstruct {\n+\t\t\tuint8_t d0[SSSNIC_TCAM_KEY_SIZE];\n+\t\t\tuint8_t d1[SSSNIC_TCAM_KEY_SIZE];\n+\t\t} key;\n+\t} data;\n+};\n+\n+struct sssnic_tcam_entry_del_cmd {\n+\tstruct sssnic_cmd_common common;\n+\tuint16_t function;\n+\tuint8_t type;\n+\tuint8_t resv;\n+\tuint32_t start; /* start index of entry to be deleted */\n+\tuint32_t num; /* number of entries to be deleted */\n+};\n+\n #endif /* _SSSNIC_CMD_H_ */\ndiff --git a/drivers/net/sssnic/base/sssnic_hw.h b/drivers/net/sssnic/base/sssnic_hw.h\nindex 4820212543..6a2d980d5a 100644\n--- a/drivers/net/sssnic/base/sssnic_hw.h\n+++ b/drivers/net/sssnic/base/sssnic_hw.h\n@@ -96,6 +96,9 @@ enum sssnic_module {\n \tSSSNIC_NETIF_MODULE = 14,\n };\n \n+#define SSSNIC_TCAM_KEY_SIZE 44\n+#define SSSNIC_TCAM_MAX_ENTRY_NUM 4096\n+\n int sssnic_hw_init(struct sssnic_hw *hw);\n void sssnic_hw_shutdown(struct sssnic_hw *hw);\n void sssnic_msix_state_set(struct sssnic_hw *hw, uint16_t msix_id, int state);\ndiff --git a/drivers/net/sssnic/base/sssnic_misc.h b/drivers/net/sssnic/base/sssnic_misc.h\nindex e30691caef..a1e268710e 100644\n--- a/drivers/net/sssnic/base/sssnic_misc.h\n+++ b/drivers/net/sssnic/base/sssnic_misc.h\n@@ -42,4 +42,11 @@ sssnic_mem_be_to_cpu_32(void *in, void *out, int size)\n \t}\n }\n \n+static inline bool\n+sssnic_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 #endif /* _SSSNIC_MISC_H_ */\ndiff --git a/drivers/net/sssnic/meson.build b/drivers/net/sssnic/meson.build\nindex 3541b75c30..03d60f08ec 100644\n--- a/drivers/net/sssnic/meson.build\n+++ b/drivers/net/sssnic/meson.build\n@@ -23,4 +23,6 @@ sources = files(\n         'sssnic_ethdev_tx.c',\n         'sssnic_ethdev_stats.c',\n         'sssnic_ethdev_rss.c',\n+        'sssnic_ethdev_fdir.c',\n+        'sssnic_ethdev_flow.c',\n )\ndiff --git a/drivers/net/sssnic/sssnic_ethdev.c b/drivers/net/sssnic/sssnic_ethdev.c\nindex 8a1ccff70b..545833fb55 100644\n--- a/drivers/net/sssnic/sssnic_ethdev.c\n+++ b/drivers/net/sssnic/sssnic_ethdev.c\n@@ -14,6 +14,8 @@\n #include \"sssnic_ethdev_tx.h\"\n #include \"sssnic_ethdev_stats.h\"\n #include \"sssnic_ethdev_rss.h\"\n+#include \"sssnic_ethdev_fdir.h\"\n+#include \"sssnic_ethdev_flow.h\"\n \n static int sssnic_ethdev_init(struct rte_eth_dev *ethdev);\n static void sssnic_ethdev_vlan_filter_clean(struct rte_eth_dev *ethdev);\n@@ -345,6 +347,7 @@ sssnic_ethdev_release(struct rte_eth_dev *ethdev)\n \tsssnic_ethdev_link_intr_disable(ethdev);\n \tsssnic_ethdev_tx_queue_all_release(ethdev);\n \tsssnic_ethdev_rx_queue_all_release(ethdev);\n+\tsssnic_ethdev_fdir_shutdown(ethdev);\n \tsssnic_ethdev_mac_addrs_clean(ethdev);\n \tsssnic_hw_shutdown(hw);\n \trte_free(hw);\n@@ -951,6 +954,7 @@ static const struct eth_dev_ops sssnic_ethdev_ops = {\n \t.flow_ctrl_get = sssnic_ethdev_flow_ctrl_get,\n \t.vlan_offload_set = sssnic_ethdev_vlan_offload_set,\n \t.vlan_filter_set = sssnic_ethdev_vlan_filter_set,\n+\t.flow_ops_get = sssnic_ethdev_flow_ops_get,\n };\n \n static int\n@@ -991,6 +995,12 @@ sssnic_ethdev_init(struct rte_eth_dev *ethdev)\n \t\tgoto mac_addrs_init_fail;\n \t}\n \n+\tret = sssnic_ethdev_fdir_init(ethdev);\n+\tif (ret) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to initialize fdir info\");\n+\t\tgoto fdir_init_fail;\n+\t}\n+\n \tnetdev->max_num_rxq = SSSNIC_MAX_NUM_RXQ(hw);\n \tnetdev->max_num_txq = SSSNIC_MAX_NUM_TXQ(hw);\n \n@@ -1001,6 +1011,8 @@ sssnic_ethdev_init(struct rte_eth_dev *ethdev)\n \n \treturn 0;\n \n+fdir_init_fail:\n+\tsssnic_ethdev_mac_addrs_clean(ethdev);\n mac_addrs_init_fail:\n \tsssnic_hw_shutdown(0);\n \treturn ret;\ndiff --git a/drivers/net/sssnic/sssnic_ethdev.h b/drivers/net/sssnic/sssnic_ethdev.h\nindex f19b2bd88f..0ca933b53b 100644\n--- a/drivers/net/sssnic/sssnic_ethdev.h\n+++ b/drivers/net/sssnic/sssnic_ethdev.h\n@@ -82,6 +82,7 @@ struct sssnic_netdev {\n \tvoid *hw;\n \tstruct rte_ether_addr *mcast_addrs;\n \tstruct rte_ether_addr default_addr;\n+\tstruct sssnic_ethdev_fdir_info *fdir_info;\n \tuint16_t max_num_txq;\n \tuint16_t max_num_rxq;\n \tuint16_t num_started_rxqs;\ndiff --git a/drivers/net/sssnic/sssnic_ethdev_fdir.c b/drivers/net/sssnic/sssnic_ethdev_fdir.c\nnew file mode 100644\nindex 0000000000..cec9fb219f\n--- /dev/null\n+++ b/drivers/net/sssnic/sssnic_ethdev_fdir.c\n@@ -0,0 +1,1017 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd.\n+ */\n+\n+#include <rte_common.h>\n+#include <rte_tailq.h>\n+#include <ethdev_pci.h>\n+\n+#include \"sssnic_log.h\"\n+#include \"sssnic_ethdev.h\"\n+#include \"sssnic_ethdev_fdir.h\"\n+#include \"base/sssnic_hw.h\"\n+#include \"base/sssnic_api.h\"\n+\n+#define SSSNIC_NETDEV_FDIR_INFO(netdev) ((netdev)->fdir_info)\n+#define SSSNIC_ETHDEV_FDIR_INFO(ethdev)                                        \\\n+\t(SSSNIC_NETDEV_FDIR_INFO(SSSNIC_ETHDEV_PRIVATE(ethdev)))\n+\n+enum {\n+\tSSSNIC_ETHDEV_PTYPE_INVAL = 0,\n+\tSSSNIC_ETHDEV_PTYPE_ARP = 1,\n+\tSSSNIC_ETHDEV_PTYPE_ARP_REQ = 2,\n+\tSSSNIC_ETHDEV_PTYPE_ARP_REP = 3,\n+\tSSSNIC_ETHDEV_PTYPE_RARP = 4,\n+\tSSSNIC_ETHDEV_PTYPE_LACP = 5,\n+\tSSSNIC_ETHDEV_PTYPE_LLDP = 6,\n+\tSSSNIC_ETHDEV_PTYPE_OAM = 7,\n+\tSSSNIC_ETHDEV_PTYPE_CDCP = 8,\n+\tSSSNIC_ETHDEV_PTYPE_CNM = 9,\n+\tSSSNIC_ETHDEV_PTYPE_ECP = 10,\n+};\n+\n+#define SSSNIC_ETHDEV_TCAM_ENTRY_INVAL_IDX 0xffff\n+struct sssnic_ethdev_fdir_entry {\n+\tTAILQ_ENTRY(sssnic_ethdev_fdir_entry) node;\n+\tstruct sssnic_ethdev_tcam_block *tcam_block;\n+\tuint32_t tcam_entry_idx;\n+\tint enabled;\n+\tstruct sssnic_ethdev_fdir_rule *rule;\n+};\n+\n+#define SSSNIC_ETHDEV_TCAM_BLOCK_SZ 16\n+struct sssnic_ethdev_tcam_block {\n+\tTAILQ_ENTRY(sssnic_ethdev_tcam_block) node;\n+\tuint16_t id;\n+\tuint16_t used_entries;\n+\tuint8_t entries_status[SSSNIC_ETHDEV_TCAM_BLOCK_SZ]; /* 0: IDLE, 1: USED */\n+};\n+\n+struct sssnic_ethdev_tcam {\n+\tTAILQ_HEAD(, sssnic_ethdev_tcam_block) block_list;\n+\tuint16_t num_blocks;\n+\tuint16_t used_entries; /* Count of used entries */\n+\tint enabled;\n+};\n+\n+struct sssnic_ethdev_fdir_info {\n+\tstruct rte_eth_dev *ethdev;\n+\tstruct sssnic_ethdev_tcam tcam;\n+\tuint32_t num_entries;\n+\tTAILQ_HEAD(, sssnic_ethdev_fdir_entry) ethertype_entry_list;\n+\tTAILQ_HEAD(, sssnic_ethdev_fdir_entry) flow_entry_list;\n+};\n+\n+static int\n+sssnic_ethdev_tcam_init(struct rte_eth_dev *ethdev)\n+{\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tstruct sssnic_ethdev_fdir_info *fdir_info;\n+\n+\tfdir_info = SSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\tTAILQ_INIT(&fdir_info->tcam.block_list);\n+\n+\tsssnic_tcam_disable_and_flush(hw);\n+\n+\treturn 0;\n+}\n+\n+static void\n+sssnic_ethdev_tcam_shutdown(struct rte_eth_dev *ethdev)\n+{\n+\tstruct sssnic_ethdev_fdir_info *fdir_info;\n+\tstruct sssnic_ethdev_tcam *tcam;\n+\tstruct sssnic_ethdev_tcam_block *block, *tmp;\n+\n+\tfdir_info = SSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\ttcam = &fdir_info->tcam;\n+\n+\tRTE_TAILQ_FOREACH_SAFE(block, &tcam->block_list, node, tmp)\n+\t{\n+\t\tTAILQ_REMOVE(&tcam->block_list, block, node);\n+\t\trte_free(block);\n+\t}\n+}\n+\n+static int\n+sssnic_ethdev_tcam_enable(struct rte_eth_dev *ethdev)\n+{\n+\tstruct sssnic_ethdev_fdir_info *fdir_info;\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tint ret;\n+\n+\tfdir_info = SSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\n+\tif (!fdir_info->tcam.enabled) {\n+\t\tret = sssnic_tcam_enable_set(hw, 1);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to enable TCAM\");\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\tfdir_info->tcam.enabled = 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_tcam_disable(struct rte_eth_dev *ethdev)\n+{\n+\tstruct sssnic_ethdev_fdir_info *fdir_info;\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tint ret;\n+\n+\tfdir_info = SSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\n+\tif (fdir_info->tcam.enabled) {\n+\t\tret = sssnic_tcam_enable_set(hw, 0);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to enable TCAM\");\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\tfdir_info->tcam.enabled = 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_tcam_block_alloc(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_tcam_block **block)\n+{\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tstruct sssnic_ethdev_fdir_info *fdir_info =\n+\t\tSSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\tstruct sssnic_ethdev_tcam_block *new;\n+\tint ret;\n+\n+\tnew = rte_zmalloc(\"sssnic_tcam_block\", sizeof(*new), 0);\n+\tif (new == NULL) {\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\"Failed to allocate memory for tcam block struct!\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tret = sssnic_tcam_block_alloc(hw, &new->id);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to alloc tcam block!\");\n+\t\trte_free(new);\n+\t\treturn ret;\n+\t}\n+\n+\tTAILQ_INSERT_HEAD(&fdir_info->tcam.block_list, new, node);\n+\tfdir_info->tcam.num_blocks++;\n+\n+\tif (block != NULL)\n+\t\t*block = new;\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_tcam_block_free(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_tcam_block *block)\n+{\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tstruct sssnic_ethdev_fdir_info *fdir_info =\n+\t\tSSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\tint ret;\n+\n+\tret = sssnic_tcam_block_free(hw, block->id);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to free tcam block:%u!\", block->id);\n+\t\treturn ret;\n+\t}\n+\n+\tTAILQ_REMOVE(&fdir_info->tcam.block_list, block, node);\n+\tfdir_info->tcam.num_blocks--;\n+\trte_free(block);\n+\n+\treturn 0;\n+}\n+\n+static struct sssnic_ethdev_tcam_block *\n+sssnic_ethdev_available_tcam_block_lookup(struct sssnic_ethdev_tcam *tcam)\n+{\n+\tstruct sssnic_ethdev_tcam_block *block;\n+\n+\tTAILQ_FOREACH(block, &tcam->block_list, node)\n+\t{\n+\t\tif (block->used_entries < SSSNIC_ETHDEV_TCAM_BLOCK_SZ)\n+\t\t\treturn block;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static int\n+sssnic_ethdev_tcam_block_entry_alloc(struct sssnic_ethdev_tcam_block *block,\n+\tuint32_t *entry_idx)\n+{\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < SSSNIC_ETHDEV_TCAM_BLOCK_SZ; i++) {\n+\t\tif (block->entries_status[i] == 0) {\n+\t\t\t*entry_idx = i;\n+\t\t\tblock->entries_status[i] = 1;\n+\t\t\tblock->used_entries++;\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\treturn -ENOMEM;\n+}\n+\n+static int\n+sssnic_ethdev_tcam_block_entry_free(struct sssnic_ethdev_tcam_block *block,\n+\tuint32_t entry_idx)\n+{\n+\tif (block != NULL && entry_idx < SSSNIC_ETHDEV_TCAM_BLOCK_SZ) {\n+\t\tif (block->entries_status[entry_idx] == 1) {\n+\t\t\tblock->entries_status[entry_idx] = 0;\n+\t\t\tblock->used_entries--;\n+\t\t\treturn 0; /* found and freed */\n+\t\t}\n+\t}\n+\treturn -1; /* not found */\n+}\n+\n+static int\n+sssnic_ethdev_tcam_entry_alloc(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_tcam_block **block, uint32_t *entry_idx)\n+{\n+\tstruct sssnic_ethdev_fdir_info *fdir_info =\n+\t\tSSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\tstruct sssnic_ethdev_tcam *tcam;\n+\tstruct sssnic_ethdev_tcam_block *tcam_block;\n+\tint new_block = 0;\n+\tuint32_t eid;\n+\tint ret;\n+\n+\ttcam = &fdir_info->tcam;\n+\n+\tif (tcam->num_blocks == 0 ||\n+\t\ttcam->used_entries >=\n+\t\t\ttcam->num_blocks * SSSNIC_ETHDEV_TCAM_BLOCK_SZ) {\n+\t\tret = sssnic_ethdev_tcam_block_alloc(ethdev, &tcam_block);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"No TCAM memory, used block count: %u, used entries count:%u\",\n+\t\t\t\ttcam->num_blocks, tcam->used_entries);\n+\t\t\treturn ret;\n+\t\t}\n+\t\tnew_block = 1;\n+\t} else {\n+\t\ttcam_block = sssnic_ethdev_available_tcam_block_lookup(tcam);\n+\t\tif (tcam_block == NULL) {\n+\t\t\tPMD_DRV_LOG(CRIT,\n+\t\t\t\t\"No available TCAM block, used block count:%u, used entries count:%u\",\n+\t\t\t\ttcam->num_blocks, tcam->used_entries);\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\t}\n+\n+\tret = sssnic_ethdev_tcam_block_entry_alloc(tcam_block, &eid);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(CRIT,\n+\t\t\t\"No available entry in TCAM block, block idx:%u, used entries:%u\",\n+\t\t\ttcam_block->id, tcam_block->used_entries);\n+\t\tif (unlikely(new_block))\n+\t\t\tsssnic_ethdev_tcam_block_free(ethdev, tcam_block);\n+\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\ttcam->used_entries++;\n+\n+\t*block = tcam_block;\n+\t*entry_idx = eid;\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_tcam_entry_free(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_tcam_block *tcam_block, uint32_t entry_idx)\n+{\n+\tint ret;\n+\tstruct sssnic_ethdev_fdir_info *fdir_info =\n+\t\tSSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\tstruct sssnic_ethdev_tcam *tcam;\n+\n+\ttcam = &fdir_info->tcam;\n+\n+\tret = sssnic_ethdev_tcam_block_entry_free(tcam_block, entry_idx);\n+\tif (ret != 0)\n+\t\treturn 0; /* not found was considered as success */\n+\n+\tif (tcam_block->used_entries == 0) {\n+\t\tret = sssnic_ethdev_tcam_block_free(ethdev, tcam_block);\n+\t\tif (ret != 0)\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to free TCAM block:%u\",\n+\t\t\t\ttcam_block->id);\n+\t}\n+\n+\ttcam->used_entries--;\n+\treturn 0;\n+}\n+\n+static void\n+sssnic_ethdev_tcam_entry_init(struct sssnic_ethdev_fdir_flow_match *flow,\n+\tstruct sssnic_tcam_entry *entry)\n+{\n+\tuint8_t i;\n+\tuint8_t *flow_key;\n+\tuint8_t *flow_mask;\n+\n+\tflow_key = (uint8_t *)&flow->key;\n+\tflow_mask = (uint8_t *)&flow->mask;\n+\n+\tfor (i = 0; i < sizeof(entry->key.data0); i++) {\n+\t\tentry->key.data1[i] = flow_key[i] & flow_mask[i];\n+\t\tentry->key.data0[i] =\n+\t\t\tentry->key.data1[i] ^ flow_mask[i];\n+\t}\n+}\n+\n+\n+static struct sssnic_ethdev_fdir_entry *\n+sssnic_ethdev_fdir_entry_lookup(struct sssnic_ethdev_fdir_info *fdir_info,\n+\tstruct sssnic_ethdev_fdir_rule *rule)\n+{\n+\tstruct sssnic_ethdev_fdir_entry *e;\n+\tstruct sssnic_ethdev_fdir_match *m;\n+\tstruct sssnic_ethdev_fdir_match *match = &rule->match;\n+\n+\t/* fast lookup */\n+\tif (rule->cookie != NULL)\n+\t\treturn (struct sssnic_ethdev_fdir_entry *)rule->cookie;\n+\n+\tif (rule->match.type == SSSNIC_ETHDEV_FDIR_MATCH_FLOW) {\n+\t\tTAILQ_FOREACH(e, &fdir_info->flow_entry_list, node)\n+\t\t{\n+\t\t\tm = &e->rule->match;\n+\t\t\tif (memcmp(&match->flow, &m->flow, sizeof(m->flow)) ==\n+\t\t\t\t0)\n+\t\t\t\treturn e;\n+\t\t}\n+\t} else if (rule->match.type == SSSNIC_ETHDEV_FDIR_MATCH_ETHERTYPE) {\n+\t\tTAILQ_FOREACH(e, &fdir_info->ethertype_entry_list, node)\n+\t\t{\n+\t\t\tm = &e->rule->match;\n+\t\t\tif (match->ethertype.key.ether_type ==\n+\t\t\t\tm->ethertype.key.ether_type)\n+\t\t\t\treturn e;\n+\t\t}\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static inline void\n+sssnic_ethdev_fdir_entry_add(struct sssnic_ethdev_fdir_info *fdir_info,\n+\tstruct sssnic_ethdev_fdir_entry *entry)\n+{\n+\tif (entry->rule->match.type == SSSNIC_ETHDEV_FDIR_MATCH_ETHERTYPE)\n+\t\tTAILQ_INSERT_TAIL(&fdir_info->ethertype_entry_list, entry,\n+\t\t\tnode);\n+\telse\n+\t\tTAILQ_INSERT_TAIL(&fdir_info->flow_entry_list, entry, node);\n+\n+\tfdir_info->num_entries++;\n+}\n+\n+static inline void\n+sssnic_ethdev_fdir_entry_del(struct sssnic_ethdev_fdir_info *fdir_info,\n+\tstruct sssnic_ethdev_fdir_entry *entry)\n+{\n+\tif (entry->rule->match.type == SSSNIC_ETHDEV_FDIR_MATCH_ETHERTYPE)\n+\t\tTAILQ_REMOVE(&fdir_info->ethertype_entry_list, entry, node);\n+\telse\n+\t\tTAILQ_REMOVE(&fdir_info->flow_entry_list, entry, node);\n+\n+\tfdir_info->num_entries--;\n+}\n+\n+static int\n+sssnic_ethdev_fdir_arp_pkt_filter_set(struct rte_eth_dev *ethdev, uint16_t qid,\n+\tint enabled)\n+{\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tint ret;\n+\n+\tret = sssnic_tcam_packet_type_filter_set(hw, SSSNIC_ETHDEV_PTYPE_ARP,\n+\t\tqid, enabled);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to %s ARP packet filter!\",\n+\t\t\tenabled ? \"enable\" : \"disable\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = sssnic_tcam_packet_type_filter_set(hw,\n+\t\tSSSNIC_ETHDEV_PTYPE_ARP_REQ, qid, enabled);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to %s ARP request packet filter!\",\n+\t\t\tenabled ? \"enable\" : \"disable\");\n+\t\tgoto set_arp_req_fail;\n+\t}\n+\n+\tret = sssnic_tcam_packet_type_filter_set(hw,\n+\t\tSSSNIC_ETHDEV_PTYPE_ARP_REP, qid, enabled);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to %s ARP reply packet filter!\",\n+\t\t\tenabled ? \"enable\" : \"disable\");\n+\t\tgoto set_arp_rep_fail;\n+\t}\n+\n+\treturn 0;\n+\n+set_arp_rep_fail:\n+\tsssnic_tcam_packet_type_filter_set(hw, SSSNIC_ETHDEV_PTYPE_ARP_REQ, qid,\n+\t\t!enabled);\n+set_arp_req_fail:\n+\tsssnic_tcam_packet_type_filter_set(hw, SSSNIC_ETHDEV_PTYPE_ARP, qid,\n+\t\t!enabled);\n+\n+\treturn ret;\n+}\n+\n+static int\n+sssnic_ethdev_fdir_slow_pkt_filter_set(struct rte_eth_dev *ethdev, uint16_t qid,\n+\tint enabled)\n+{\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tint ret;\n+\n+\tret = sssnic_tcam_packet_type_filter_set(hw, SSSNIC_ETHDEV_PTYPE_LACP,\n+\t\tqid, enabled);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to %s LACP packet filter!\",\n+\t\t\tenabled ? \"enable\" : \"disable\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = sssnic_tcam_packet_type_filter_set(hw, SSSNIC_ETHDEV_PTYPE_OAM,\n+\t\tqid, enabled);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to %s OAM packet filter!\",\n+\t\t\tenabled ? \"enable\" : \"disable\");\n+\n+\t\tsssnic_tcam_packet_type_filter_set(hw, SSSNIC_ETHDEV_PTYPE_LACP,\n+\t\t\tqid, !enabled);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int\n+sssnic_ethdev_fdir_lldp_pkt_filter_set(struct rte_eth_dev *ethdev, uint16_t qid,\n+\tint enabled)\n+{\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tint ret;\n+\n+\tret = sssnic_tcam_packet_type_filter_set(hw, SSSNIC_ETHDEV_PTYPE_LLDP,\n+\t\tqid, enabled);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to %s LLDP packet filter!\",\n+\t\t\tenabled ? \"enable\" : \"disable\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = sssnic_tcam_packet_type_filter_set(hw, SSSNIC_ETHDEV_PTYPE_CDCP,\n+\t\tqid, enabled);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to %s CDCP packet filter!\",\n+\t\t\tenabled ? \"enable\" : \"disable\");\n+\n+\t\tsssnic_tcam_packet_type_filter_set(hw, SSSNIC_ETHDEV_PTYPE_LLDP,\n+\t\t\tqid, !enabled);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int\n+sssnic_ethdev_fdir_pkt_filter_set(struct rte_eth_dev *ethdev,\n+\tuint16_t ether_type, uint16_t qid, int enabled)\n+{\n+\tint ret;\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\n+\tswitch (ether_type) {\n+\tcase RTE_ETHER_TYPE_ARP:\n+\t\tret = sssnic_ethdev_fdir_arp_pkt_filter_set(ethdev, qid,\n+\t\t\tenabled);\n+\t\tbreak;\n+\tcase RTE_ETHER_TYPE_RARP:\n+\t\tret = sssnic_tcam_packet_type_filter_set(hw,\n+\t\t\tSSSNIC_ETHDEV_PTYPE_RARP, qid, enabled);\n+\t\tbreak;\n+\tcase RTE_ETHER_TYPE_SLOW:\n+\t\tret = sssnic_ethdev_fdir_slow_pkt_filter_set(ethdev, qid,\n+\t\t\tenabled);\n+\t\tbreak;\n+\tcase RTE_ETHER_TYPE_LLDP:\n+\t\tret = sssnic_ethdev_fdir_lldp_pkt_filter_set(ethdev, qid,\n+\t\t\tenabled);\n+\t\tbreak;\n+\tcase 0x22e7: /* CNM ether type */\n+\t\tret = sssnic_tcam_packet_type_filter_set(hw,\n+\t\t\tSSSNIC_ETHDEV_PTYPE_CNM, qid, enabled);\n+\t\tbreak;\n+\tcase 0x8940: /* ECP ether type */\n+\t\tret = sssnic_tcam_packet_type_filter_set(hw,\n+\t\t\tSSSNIC_ETHDEV_PTYPE_ECP, qid, enabled);\n+\t\tbreak;\n+\tdefault:\n+\t\tPMD_DRV_LOG(ERR, \"Ethertype 0x%x is not supported to filter!\",\n+\t\t\tether_type);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ret != 0)\n+\t\tPMD_DRV_LOG(ERR, \"Failed to %s filter for ether type: %x.\",\n+\t\t\tenabled ? \"enable\" : \"disable\", ether_type);\n+\n+\treturn ret;\n+}\n+\n+static inline struct sssnic_ethdev_fdir_entry *\n+sssnic_ethdev_fdir_entry_alloc(void)\n+{\n+\tstruct sssnic_ethdev_fdir_entry *e;\n+\n+\te = rte_zmalloc(\"sssnic_fdir_entry\", sizeof(*e), 0);\n+\tif (e != NULL)\n+\t\te->tcam_entry_idx = SSSNIC_ETHDEV_TCAM_ENTRY_INVAL_IDX;\n+\telse\n+\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\"Failed to allocate memory for fdir entry struct!\");\n+\n+\treturn e;\n+}\n+\n+static inline void\n+sssnic_ethdev_fdir_entry_free(struct sssnic_ethdev_fdir_entry *e)\n+{\n+\tif (e != NULL)\n+\t\trte_free(e);\n+}\n+\n+/* Apply fdir rule to HW */\n+static int\n+sssnic_ethdev_fdir_entry_enable(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_fdir_entry *entry)\n+{\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tstruct sssnic_tcam_entry tcam_entry;\n+\tint ret;\n+\n+\tif (unlikely(entry->rule == NULL)) {\n+\t\tPMD_DRV_LOG(ERR, \"fdir rule is null!\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (entry->enabled)\n+\t\treturn 0;\n+\n+\tif (entry->tcam_entry_idx != SSSNIC_ETHDEV_TCAM_ENTRY_INVAL_IDX) {\n+\t\tmemset(&tcam_entry, 0, sizeof(tcam_entry));\n+\t\tsssnic_ethdev_tcam_entry_init(&entry->rule->match.flow,\n+\t\t\t&tcam_entry);\n+\t\ttcam_entry.result.qid = entry->rule->action.qid;\n+\t\ttcam_entry.index =\n+\t\t\tentry->tcam_entry_idx +\n+\t\t\t(entry->tcam_block->id * SSSNIC_ETHDEV_TCAM_BLOCK_SZ);\n+\n+\t\tret = sssnic_tcam_entry_add(hw, &tcam_entry);\n+\t\tif (ret != 0)\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Failed to add TCAM entry, block:%u, entry:%u, tcam_entry:%u\",\n+\t\t\t\tentry->tcam_block->id, entry->tcam_entry_idx,\n+\t\t\t\ttcam_entry.index);\n+\n+\t} else {\n+\t\tret = sssnic_ethdev_fdir_pkt_filter_set(ethdev,\n+\t\t\tentry->rule->match.ethertype.key.ether_type,\n+\t\t\tentry->rule->action.qid, 1);\n+\t\tif (ret != 0)\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to enable ethertype(%x) filter\",\n+\t\t\t\tentry->rule->match.ethertype.key.ether_type);\n+\t}\n+\n+\tentry->enabled = 1;\n+\n+\treturn ret;\n+}\n+\n+/* remove fdir rule from HW */\n+static int\n+sssnic_ethdev_fdir_entry_disable(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_fdir_entry *entry)\n+{\n+\tstruct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev);\n+\tuint32_t tcam_entry_idx;\n+\tint ret;\n+\n+\tif (unlikely(entry->rule == NULL)) {\n+\t\tPMD_DRV_LOG(ERR, \"fdir rule is null!\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!entry->enabled)\n+\t\treturn 0;\n+\n+\tif (entry->tcam_entry_idx != SSSNIC_ETHDEV_TCAM_ENTRY_INVAL_IDX) {\n+\t\ttcam_entry_idx =\n+\t\t\tentry->tcam_entry_idx +\n+\t\t\t(entry->tcam_block->id * SSSNIC_ETHDEV_TCAM_BLOCK_SZ);\n+\n+\t\tret = sssnic_tcam_entry_del(hw, tcam_entry_idx);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Failed to del TCAM entry, block:%u, entry:%u\",\n+\t\t\t\tentry->tcam_block->id, entry->tcam_entry_idx);\n+\t\t\treturn ret;\n+\t\t}\n+\t} else {\n+\t\tret = sssnic_ethdev_fdir_pkt_filter_set(ethdev,\n+\t\t\tentry->rule->match.ethertype.key.ether_type,\n+\t\t\tentry->rule->action.qid, 0);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Failed to disable ethertype(%x) filter\",\n+\t\t\t\tentry->rule->match.ethertype.key.ether_type);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tentry->enabled = 0;\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_fdir_ethertype_rule_add(struct sssnic_ethdev_fdir_info *fdir_info,\n+\tstruct sssnic_ethdev_fdir_rule *rule)\n+{\n+\tstruct sssnic_ethdev_fdir_entry *fdir_entry;\n+\tint ret;\n+\n+\tfdir_entry = sssnic_ethdev_fdir_entry_alloc();\n+\tif (fdir_entry == NULL)\n+\t\treturn -ENOMEM;\n+\n+\tfdir_entry->rule = rule;\n+\n+\tret = sssnic_ethdev_fdir_entry_enable(fdir_info->ethdev, fdir_entry);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to enable ethertype(%u) entry\",\n+\t\t\trule->match.ethertype.key.ether_type);\n+\n+\t\tsssnic_ethdev_fdir_entry_free(fdir_entry);\n+\n+\t\treturn ret;\n+\t}\n+\n+\trule->cookie = fdir_entry;\n+\tsssnic_ethdev_fdir_entry_add(fdir_info, fdir_entry);\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_fdir_ethertype_rule_del(struct sssnic_ethdev_fdir_info *fdir_info,\n+\tstruct sssnic_ethdev_fdir_rule *rule)\n+{\n+\tstruct sssnic_ethdev_fdir_entry *fdir_entry;\n+\tint ret;\n+\n+\tfdir_entry = (struct sssnic_ethdev_fdir_entry *)rule->cookie;\n+\n+\tret = sssnic_ethdev_fdir_entry_disable(fdir_info->ethdev, fdir_entry);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to disable ethertype(%u) entry\",\n+\t\t\trule->match.ethertype.key.ether_type);\n+\t\treturn ret;\n+\t}\n+\n+\trule->cookie = NULL;\n+\tsssnic_ethdev_fdir_entry_del(fdir_info, fdir_entry);\n+\tsssnic_ethdev_fdir_entry_free(fdir_entry);\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_fdir_flow_rule_add(struct sssnic_ethdev_fdir_info *fdir_info,\n+\tstruct sssnic_ethdev_fdir_rule *rule)\n+{\n+\tstruct sssnic_ethdev_fdir_entry *fdir_entry;\n+\tint ret;\n+\n+\tfdir_entry = sssnic_ethdev_fdir_entry_alloc();\n+\tif (fdir_entry == NULL)\n+\t\treturn -ENOMEM;\n+\n+\tfdir_entry->rule = rule;\n+\n+\tret = sssnic_ethdev_tcam_entry_alloc(fdir_info->ethdev,\n+\t\t&fdir_entry->tcam_block, &fdir_entry->tcam_entry_idx);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to alloc TCAM entry\");\n+\t\tgoto tcam_entry_alloc_fail;\n+\t}\n+\n+\tret = sssnic_ethdev_fdir_entry_enable(fdir_info->ethdev, fdir_entry);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to enable fdir flow entry\");\n+\t\tgoto fdir_entry_enable_fail;\n+\t}\n+\n+\trule->cookie = fdir_entry;\n+\tsssnic_ethdev_fdir_entry_add(fdir_info, fdir_entry);\n+\n+\treturn 0;\n+\n+fdir_entry_enable_fail:\n+\tsssnic_ethdev_tcam_entry_free(fdir_info->ethdev, fdir_entry->tcam_block,\n+\t\tfdir_entry->tcam_entry_idx);\n+tcam_entry_alloc_fail:\n+\tsssnic_ethdev_fdir_entry_free(fdir_entry);\n+\n+\treturn ret;\n+}\n+\n+static int\n+sssnic_ethdev_fdir_flow_rule_del(struct sssnic_ethdev_fdir_info *fdir_info,\n+\tstruct sssnic_ethdev_fdir_rule *rule)\n+{\n+\tstruct sssnic_ethdev_fdir_entry *fdir_entry;\n+\tint ret;\n+\n+\tfdir_entry = (struct sssnic_ethdev_fdir_entry *)rule->cookie;\n+\n+\tret = sssnic_ethdev_fdir_entry_disable(fdir_info->ethdev, fdir_entry);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to disable fdir flow entry\");\n+\t\treturn ret;\n+\t}\n+\n+\trule->cookie = NULL;\n+\tsssnic_ethdev_fdir_entry_del(fdir_info, fdir_entry);\n+\tsssnic_ethdev_fdir_entry_free(fdir_entry);\n+\n+\treturn 0;\n+}\n+\n+int\n+sssnic_ethdev_fdir_rule_add(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_fdir_rule *rule)\n+{\n+\tstruct sssnic_ethdev_fdir_info *fdir_info;\n+\tint ret;\n+\n+\tfdir_info = SSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\n+\tif (sssnic_ethdev_fdir_entry_lookup(fdir_info, rule) != NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"FDIR rule exists!\");\n+\t\treturn -EEXIST;\n+\t}\n+\n+\tif (rule->match.type == SSSNIC_ETHDEV_FDIR_MATCH_ETHERTYPE) {\n+\t\tret = sssnic_ethdev_fdir_ethertype_rule_add(fdir_info, rule);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to add fdir ethertype rule\");\n+\t\t\treturn ret;\n+\t\t}\n+\t\tPMD_DRV_LOG(DEBUG,\n+\t\t\t\"Added fdir ethertype rule, total number of rules: %u\",\n+\t\t\tfdir_info->num_entries);\n+\t} else {\n+\t\tret = sssnic_ethdev_fdir_flow_rule_add(fdir_info, rule);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to add fdir flow rule\");\n+\t\t\treturn ret;\n+\t\t}\n+\t\tPMD_DRV_LOG(DEBUG,\n+\t\t\t\"Added fdir flow rule, total number of rules: %u\",\n+\t\t\tfdir_info->num_entries);\n+\t}\n+\n+\tret = sssnic_ethdev_tcam_enable(ethdev);\n+\tif (ret != 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to enable TCAM\");\n+\t\tsssnic_ethdev_fdir_flow_rule_del(fdir_info, rule);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int\n+sssnic_ethdev_fdir_rule_del(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_fdir_rule *fdir_rule)\n+{\n+\tstruct sssnic_ethdev_fdir_info *fdir_info;\n+\tstruct sssnic_ethdev_fdir_entry *entry;\n+\tstruct sssnic_ethdev_fdir_rule *rule;\n+\tint ret;\n+\n+\tfdir_info = SSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\n+\tentry = sssnic_ethdev_fdir_entry_lookup(fdir_info, fdir_rule);\n+\tif (entry == NULL)\n+\t\treturn 0;\n+\n+\trule = entry->rule;\n+\tif (rule != fdir_rule)\n+\t\treturn 0;\n+\n+\tif (rule->match.type == SSSNIC_ETHDEV_FDIR_MATCH_ETHERTYPE) {\n+\t\tret = sssnic_ethdev_fdir_ethertype_rule_del(fdir_info, rule);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\"Failed to delete fdir ethertype rule!\");\n+\t\t\treturn ret;\n+\t\t}\n+\t\tPMD_DRV_LOG(DEBUG,\n+\t\t\t\"Deleted fdir ethertype rule, total number of rules: %u\",\n+\t\t\tfdir_info->num_entries);\n+\t} else {\n+\t\tret = sssnic_ethdev_fdir_flow_rule_del(fdir_info, rule);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to delete fdir flow rule!\");\n+\t\t\treturn ret;\n+\t\t}\n+\t\tPMD_DRV_LOG(DEBUG,\n+\t\t\t\"Deleted fdir flow rule, total number of rules: %u\",\n+\t\t\tfdir_info->num_entries);\n+\t}\n+\n+\t/* if there are no added rules, then disable TCAM */\n+\tif (fdir_info->num_entries == 0) {\n+\t\tret = sssnic_ethdev_tcam_disable(ethdev);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(NOTICE,\n+\t\t\t\t\"There are no added rules, but failed to disable TCAM\");\n+\t\t\tret = 0;\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int\n+sssnic_ethdev_fdir_rules_disable_by_queue(struct rte_eth_dev *ethdev,\n+\tuint16_t qid)\n+{\n+\tstruct sssnic_ethdev_fdir_info *fdir_info;\n+\tstruct sssnic_ethdev_fdir_entry *entry;\n+\tint ret;\n+\n+\tfdir_info = SSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\n+\tTAILQ_FOREACH(entry, &fdir_info->flow_entry_list, node)\n+\t{\n+\t\tif (entry->rule->action.qid == qid) {\n+\t\t\tret = sssnic_ethdev_fdir_entry_disable(ethdev, entry);\n+\t\t\tif (ret != 0) {\n+\t\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\t\"Failed to disable flow rule of queue:%u\",\n+\t\t\t\t\tqid);\n+\n+\t\t\t\treturn ret;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+sssnic_ethdev_fdir_rules_enable_by_queue(struct rte_eth_dev *ethdev,\n+\tuint16_t qid)\n+{\n+\tstruct sssnic_ethdev_fdir_info *fdir_info;\n+\tstruct sssnic_ethdev_fdir_entry *entry;\n+\tint ret;\n+\n+\tfdir_info = SSSNIC_ETHDEV_FDIR_INFO(ethdev);\n+\n+\tTAILQ_FOREACH(entry, &fdir_info->flow_entry_list, node)\n+\t{\n+\t\tif (entry->rule->action.qid == qid) {\n+\t\t\tret = sssnic_ethdev_fdir_entry_enable(ethdev, entry);\n+\t\t\tif (ret != 0) {\n+\t\t\t\tPMD_DRV_LOG(ERR,\n+\t\t\t\t\t\"Failed to enable flow rule of queue:%u\",\n+\t\t\t\t\tqid);\n+\n+\t\t\t\treturn ret;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+sssnic_ethdev_fdir_rules_flush(struct rte_eth_dev *ethdev)\n+{\n+\tstruct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev);\n+\tstruct sssnic_ethdev_fdir_entry *entry, *tmp;\n+\tstruct sssnic_ethdev_fdir_rule *rule;\n+\tint ret;\n+\n+\tRTE_TAILQ_FOREACH_SAFE(entry, &netdev->fdir_info->flow_entry_list, node,\n+\t\ttmp)\n+\t{\n+\t\trule = entry->rule;\n+\t\tret = sssnic_ethdev_fdir_entry_disable(ethdev, entry);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to disable fdir flow entry\");\n+\t\t\treturn ret;\n+\t\t}\n+\t\tTAILQ_REMOVE(&netdev->fdir_info->flow_entry_list, entry, node);\n+\t\tsssnic_ethdev_fdir_entry_free(entry);\n+\t\tsssnic_ethdev_fdir_rule_free(rule);\n+\t}\n+\n+\tRTE_TAILQ_FOREACH_SAFE(entry, &netdev->fdir_info->ethertype_entry_list,\n+\t\tnode, tmp)\n+\t{\n+\t\trule = entry->rule;\n+\t\tret = sssnic_ethdev_fdir_entry_disable(ethdev, entry);\n+\t\tif (ret != 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Failed to disable ethertype(%u) entry\",\n+\t\t\t\trule->match.ethertype.key.ether_type);\n+\t\t\treturn ret;\n+\t\t}\n+\t\tTAILQ_REMOVE(&netdev->fdir_info->ethertype_entry_list, entry,\n+\t\t\tnode);\n+\t\tsssnic_ethdev_fdir_entry_free(entry);\n+\t\tsssnic_ethdev_fdir_rule_free(rule);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+sssnic_ethdev_fdir_init(struct rte_eth_dev *ethdev)\n+{\n+\tstruct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev);\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tnetdev->fdir_info = rte_zmalloc(\"sssnic_fdir_info\",\n+\t\tsizeof(struct sssnic_ethdev_fdir_info), 0);\n+\n+\tif (netdev->fdir_info == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to alloc fdir info memory for port %u\",\n+\t\t\tethdev->data->port_id);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tnetdev->fdir_info->ethdev = ethdev;\n+\n+\tTAILQ_INIT(&netdev->fdir_info->ethertype_entry_list);\n+\tTAILQ_INIT(&netdev->fdir_info->flow_entry_list);\n+\n+\tsssnic_ethdev_tcam_init(ethdev);\n+\n+\treturn 0;\n+}\n+\n+void\n+sssnic_ethdev_fdir_shutdown(struct rte_eth_dev *ethdev)\n+{\n+\tstruct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev);\n+\tstruct sssnic_ethdev_fdir_entry *entry, *tmp;\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\tif (netdev->fdir_info == NULL)\n+\t\treturn;\n+\n+\tRTE_TAILQ_FOREACH_SAFE(entry, &netdev->fdir_info->flow_entry_list, node,\n+\t\ttmp)\n+\t{\n+\t\tTAILQ_REMOVE(&netdev->fdir_info->flow_entry_list, entry, node);\n+\t\tsssnic_ethdev_fdir_entry_free(entry);\n+\t}\n+\n+\tRTE_TAILQ_FOREACH_SAFE(entry, &netdev->fdir_info->ethertype_entry_list,\n+\t\tnode, tmp)\n+\t{\n+\t\tTAILQ_REMOVE(&netdev->fdir_info->ethertype_entry_list, entry,\n+\t\t\tnode);\n+\t\tsssnic_ethdev_fdir_entry_free(entry);\n+\t}\n+\n+\tsssnic_ethdev_tcam_shutdown(ethdev);\n+\n+\trte_free(netdev->fdir_info);\n+}\ndiff --git a/drivers/net/sssnic/sssnic_ethdev_fdir.h b/drivers/net/sssnic/sssnic_ethdev_fdir.h\nnew file mode 100644\nindex 0000000000..aaf426b8f2\n--- /dev/null\n+++ b/drivers/net/sssnic/sssnic_ethdev_fdir.h\n@@ -0,0 +1,332 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd.\n+ */\n+\n+#ifndef _SSSNIC_ETHDEV_FDIR_H_\n+#define _SSSNIC_ETHDEV_FDIR_H_\n+\n+#define SSSINC_ETHDEV_FDIR_FLOW_KEY_SIZE 44\n+#define SSSNIC_ETHDEV_FDIR_FLOW_KEY_NUM_DW                                     \\\n+\t(SSSINC_ETHDEV_FDIR_FLOW_KEY_SIZE / sizeof(uint32_t))\n+\n+enum sssnic_ethdev_fdir_match_type {\n+\tSSSNIC_ETHDEV_FDIR_MATCH_ETHERTYPE = RTE_ETH_FILTER_ETHERTYPE,\n+\tSSSNIC_ETHDEV_FDIR_MATCH_FLOW = RTE_ETH_FILTER_FDIR,\n+};\n+\n+enum sssnic_ethdev_fdir_flow_ip_type {\n+\tSSSNIC_ETHDEV_FDIR_FLOW_IPV4 = 0,\n+\tSSSNIC_ETHDEV_FDIR_FLOW_IPV6 = 1,\n+};\n+\n+enum sssnic_ethdev_fdir_flow_tunnel_type {\n+\tSSSNIC_ETHDEV_FDIR_FLOW_TUNNEL_NONE = 0,\n+\tSSSNIC_ETHDEV_FDIR_FLOW_TUNNEL_VXLAN = 1,\n+};\n+\n+#define SSSNIC_ETHDEV_FDIR_FLOW_FUNC_ID_MASK 0x7fff\n+#define SSSNIC_ETHDEV_FDIR_FLOW_IP_TYPE_MASK 0x1\n+#define SSSNIC_ETHDEV_FDIR_FLOW_TUNNEL_TYPE_MASK 0xf\n+\n+struct sssnic_ethdev_fdir_ethertype_key {\n+\tuint16_t ether_type;\n+};\n+\n+struct sssnic_ethdev_fdir_ipv4_flow_key {\n+#if (RTE_BYTE_ORDER == RTE_BIG_ENDIAN)\n+\tuint32_t resvd0 : 16;\n+\tuint32_t ip_proto : 8;\n+\tuint32_t tunnel_type : 4;\n+\tuint32_t resvd1 : 4;\n+\n+\tuint32_t func_id : 15;\n+\tuint32_t ip_type : 1;\n+\tuint32_t sip_w1 : 16;\n+\n+\tuint32_t sip_w0 : 16;\n+\tuint32_t dip_w1 : 16;\n+\n+\tuint32_t dip_w0 : 16;\n+\tuint32_t resvd2 : 16;\n+\n+\tuint32_t resvd3;\n+\n+\tuint32_t resvd4 : 16;\n+\tuint32_t dport : 16;\n+\n+\tuint32_t sport : 16;\n+\tuint32_t resvd5 : 16;\n+\n+\tuint32_t resvd6 : 16;\n+\tuint32_t outer_sip_w1 : 16;\n+\n+\tuint32_t outer_sip_w0 : 16;\n+\tuint32_t outer_dip_w1 : 16;\n+\n+\tuint32_t outer_dip_w0 : 16;\n+\tuint32_t vni_w1 : 16;\n+\n+\tuint32_t vni_w0 : 16;\n+\tuint32_t resvd7 : 16;\n+#else\n+\tuint32_t resvd1 : 4;\n+\tuint32_t tunnel_type : 4;\n+\tuint32_t ip_proto : 8;\n+\tuint32_t resvd0 : 16;\n+\n+\tuint32_t sip_w1 : 16;\n+\tuint32_t ip_type : 1;\n+\tuint32_t func_id : 15;\n+\n+\tuint32_t dip_w1 : 16;\n+\tuint32_t sip_w0 : 16;\n+\n+\tuint32_t resvd2 : 16;\n+\tuint32_t dip_w0 : 16;\n+\n+\tuint32_t rsvd3;\n+\n+\tuint32_t dport : 16;\n+\tuint32_t resvd4 : 16;\n+\n+\tuint32_t resvd5 : 16;\n+\tuint32_t sport : 16;\n+\n+\tuint32_t outer_sip_w1 : 16;\n+\tuint32_t resvd6 : 16;\n+\n+\tuint32_t outer_dip_w1 : 16;\n+\tuint32_t outer_sip_w0 : 16;\n+\n+\tuint32_t vni_w1 : 16;\n+\tuint32_t outer_dip_w0 : 16;\n+\n+\tuint32_t resvd7 : 16;\n+\tuint32_t vni_w0 : 16;\n+#endif\n+};\n+\n+struct sssnic_ethdev_fdir_ipv6_flow_key {\n+#if (RTE_BYTE_ORDER == RTE_BIG_ENDIAN)\n+\tuint32_t resvd0 : 16;\n+\tuint32_t ip_proto : 8;\n+\tuint32_t tunnel_type : 4;\n+\tuint32_t resvd1 : 4;\n+\n+\tuint32_t func_id : 15;\n+\tuint32_t ip_type : 1;\n+\tuint32_t sip6_w0 : 16;\n+\n+\tuint32_t sip6_w1 : 16;\n+\tuint32_t sip6_w2 : 16;\n+\n+\tuint32_t sip6_w3 : 16;\n+\tuint32_t sip6_w4 : 16;\n+\n+\tuint32_t sip6_w5 : 16;\n+\tuint32_t sip6_w6 : 16;\n+\n+\tuint32_t sip6_w7 : 16;\n+\tuint32_t dport : 16;\n+\n+\tuint32_t sport : 16;\n+\tuint32_t dip6_w0 : 16;\n+\n+\tuint32_t dip6_w1 : 16;\n+\tuint32_t dip6_w2 : 16;\n+\n+\tuint32_t dip6_w3 : 16;\n+\tuint32_t dip6_w4 : 16;\n+\n+\tuint32_t dip6_w5 : 16;\n+\tuint32_t dip6_w6 : 16;\n+\n+\tuint32_t dip6_w7 : 16;\n+\tuint32_t resvd2 : 16;\n+#else\n+\tuint32_t resvd1 : 4;\n+\tuint32_t tunnel_type : 4;\n+\tuint32_t ip_proto : 8;\n+\tuint32_t resvd0 : 16;\n+\n+\tuint32_t sip6_w0 : 16;\n+\tuint32_t ip_type : 1;\n+\tuint32_t func_id : 15;\n+\n+\tuint32_t sip6_w2 : 16;\n+\tuint32_t sip6_w1 : 16;\n+\n+\tuint32_t sip6_w4 : 16;\n+\tuint32_t sip6_w3 : 16;\n+\n+\tuint32_t sip6_w6 : 16;\n+\tuint32_t sip6_w5 : 16;\n+\n+\tuint32_t dport : 16;\n+\tuint32_t sip6_w7 : 16;\n+\n+\tuint32_t dip6_w0 : 16;\n+\tuint32_t sport : 16;\n+\n+\tuint32_t dip6_w2 : 16;\n+\tuint32_t dip6_w1 : 16;\n+\n+\tuint32_t dip6_w4 : 16;\n+\tuint32_t dip6_w3 : 16;\n+\n+\tuint32_t dip6_w6 : 16;\n+\tuint32_t dip6_w5 : 16;\n+\n+\tuint32_t resvd2 : 16;\n+\tuint32_t dip6_w7 : 16;\n+#endif\n+};\n+\n+struct sssnic_ethdev_fdir_vxlan_ipv6_flow_key {\n+#if (RTE_BYTE_ORDER == RTE_BIG_ENDIAN)\n+\tuint32_t resvd0 : 16;\n+\tuint32_t ip_proto : 8;\n+\tuint32_t tunnel_type : 4;\n+\tuint32_t resvd1 : 4;\n+\n+\tuint32_t func_id : 15;\n+\tuint32_t ip_type : 1;\n+\tuint32_t dip6_w0 : 16;\n+\n+\tuint32_t dip6_w1 : 16;\n+\tuint32_t dip6_w2 : 16;\n+\n+\tuint32_t dip6_w3 : 16;\n+\tuint32_t dip6_w4 : 16;\n+\n+\tuint32_t dip6_w5 : 16;\n+\tuint32_t dip6_w6 : 16;\n+\n+\tuint32_t dip6_w7 : 16;\n+\tuint32_t dport : 16;\n+\n+\tuint32_t sport : 16;\n+\tuint32_t resvd2 : 16;\n+\n+\tuint32_t resvd3 : 16;\n+\tuint32_t outer_sip_w1 : 16;\n+\n+\tuint32_t outer_sip_w0 : 16;\n+\tuint32_t outer_dip_w1 : 16;\n+\n+\tuint32_t outer_dip_w0 : 16;\n+\tuint32_t vni_w1 : 16;\n+\n+\tuint32_t vni_w0 : 16;\n+\tuint32_t resvd4 : 16;\n+#else\n+\tuint32_t rsvd1 : 4;\n+\tuint32_t tunnel_type : 4;\n+\tuint32_t ip_proto : 8;\n+\tuint32_t resvd0 : 16;\n+\n+\tuint32_t dip6_w0 : 16;\n+\tuint32_t ip_type : 1;\n+\tuint32_t function_id : 15;\n+\n+\tuint32_t dip6_w2 : 16;\n+\tuint32_t dip6_w1 : 16;\n+\n+\tuint32_t dip6_w4 : 16;\n+\tuint32_t dip6_w3 : 16;\n+\n+\tuint32_t dip6_w6 : 16;\n+\tuint32_t dip6_w5 : 16;\n+\n+\tuint32_t dport : 16;\n+\tuint32_t dip6_w7 : 16;\n+\n+\tuint32_t resvd2 : 16;\n+\tuint32_t sport : 16;\n+\n+\tuint32_t outer_sip_w1 : 16;\n+\tuint32_t resvd3 : 16;\n+\n+\tuint32_t outer_dip_w1 : 16;\n+\tuint32_t outer_sip_w0 : 16;\n+\n+\tuint32_t vni_w1 : 16;\n+\tuint32_t outer_dip_w0 : 16;\n+\n+\tuint32_t resvd4 : 16;\n+\tuint32_t vni_w0 : 16;\n+#endif\n+};\n+\n+struct sssnic_ethdev_fdir_flow_key {\n+\tunion {\n+\t\tuint32_t dword[SSSNIC_ETHDEV_FDIR_FLOW_KEY_NUM_DW];\n+\t\tstruct {\n+\t\t\tstruct sssnic_ethdev_fdir_ipv4_flow_key ipv4;\n+\t\t\tstruct sssnic_ethdev_fdir_ipv6_flow_key ipv6;\n+\t\t\tstruct sssnic_ethdev_fdir_vxlan_ipv6_flow_key vxlan_ipv6;\n+\t\t};\n+\t};\n+};\n+\n+struct sssnic_ethdev_fdir_flow_match {\n+\tstruct sssnic_ethdev_fdir_flow_key key;\n+\tstruct sssnic_ethdev_fdir_flow_key mask;\n+};\n+\n+struct sssnic_ethdev_fdir_ethertype_match {\n+\tstruct sssnic_ethdev_fdir_ethertype_key key;\n+};\n+\n+struct sssnic_ethdev_fdir_match {\n+\tenum sssnic_ethdev_fdir_match_type type;\n+\tunion {\n+\t\tstruct sssnic_ethdev_fdir_flow_match flow;\n+\t\tstruct sssnic_ethdev_fdir_ethertype_match ethertype;\n+\t};\n+};\n+\n+struct sssnic_ethdev_fdir_action {\n+\tuint16_t qid;\n+};\n+\n+/* struct sssnic_ethdev_fdir_rule must be dynamically allocated in the heap */\n+struct sssnic_ethdev_fdir_rule {\n+\tstruct sssnic_ethdev_fdir_match match;\n+\tstruct sssnic_ethdev_fdir_action action;\n+\tvoid *cookie; /* low level data, initial value must be set to  NULL*/\n+};\n+\n+struct sssnic_ethdev_fdir_info;\n+\n+static inline struct sssnic_ethdev_fdir_rule *\n+sssnic_ethdev_fdir_rule_alloc(void)\n+{\n+\tstruct sssnic_ethdev_fdir_rule *rule;\n+\n+\trule = rte_zmalloc(\"sssnic_fdir_rule\",\n+\t\tsizeof(struct sssnic_ethdev_fdir_rule), 0);\n+\n+\treturn rule;\n+}\n+\n+static inline void\n+sssnic_ethdev_fdir_rule_free(struct sssnic_ethdev_fdir_rule *rule)\n+{\n+\tif (rule != NULL)\n+\t\trte_free(rule);\n+}\n+\n+int sssnic_ethdev_fdir_rules_disable_by_queue(struct rte_eth_dev *ethdev,\n+\tuint16_t qid);\n+int sssnic_ethdev_fdir_rules_enable_by_queue(struct rte_eth_dev *ethdev,\n+\tuint16_t qid);\n+int sssnic_ethdev_fdir_rule_add(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_fdir_rule *rule);\n+int sssnic_ethdev_fdir_rule_del(struct rte_eth_dev *ethdev,\n+\tstruct sssnic_ethdev_fdir_rule *fdir_rule);\n+int sssnic_ethdev_fdir_rules_flush(struct rte_eth_dev *ethdev);\n+int sssnic_ethdev_fdir_init(struct rte_eth_dev *ethdev);\n+void sssnic_ethdev_fdir_shutdown(struct rte_eth_dev *ethdev);\n+\n+#endif /* _SSSNIC_ETHDEV_FDIR_H_ */\ndiff --git a/drivers/net/sssnic/sssnic_ethdev_flow.c b/drivers/net/sssnic/sssnic_ethdev_flow.c\nnew file mode 100644\nindex 0000000000..372a5bed6b\n--- /dev/null\n+++ b/drivers/net/sssnic/sssnic_ethdev_flow.c\n@@ -0,0 +1,981 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd.\n+ */\n+\n+#include <rte_common.h>\n+#include <ethdev_pci.h>\n+#include <rte_flow_driver.h>\n+\n+#include \"sssnic_log.h\"\n+#include \"sssnic_ethdev.h\"\n+#include \"sssnic_ethdev_fdir.h\"\n+#include \"sssnic_ethdev_flow.h\"\n+#include \"base/sssnic_hw.h\"\n+#include \"base/sssnic_api.h\"\n+#include \"base/sssnic_misc.h\"\n+\n+struct rte_flow {\n+\tstruct sssnic_ethdev_fdir_rule rule;\n+};\n+\n+static enum rte_flow_item_type pattern_ethertype[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_any[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_ANY,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan_eth_ipv4[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan_any[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_ANY,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan_eth_ipv4_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan_eth_ipv4_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan_eth_ipv6[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan_eth_ipv6_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv4_udp_vxlan_eth_ipv6_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_VXLAN,\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv6[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv6_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_eth_ipv6_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+enum sssnic_ethdev_flow_type {\n+\tSSSNIC_ETHDEV_FLOW_TYPE_UNKNOWN = -1,\n+\tSSSNIC_ETHDEV_FLOW_TYPE_ETHERTYPE,\n+\tSSSNIC_ETHDEV_FLOW_TYPE_FDIR,\n+\tSSSNIC_ETHDEV_FLOW_TYPE_COUNT,\n+};\n+\n+struct sssnic_ethdev_flow_pattern {\n+\tenum rte_flow_item_type *flow_items;\n+\tenum sssnic_ethdev_flow_type type;\n+\tbool is_tunnel;\n+};\n+\n+static struct sssnic_ethdev_flow_pattern supported_flow_patterns[] = {\n+\t{ pattern_ethertype, SSSNIC_ETHDEV_FLOW_TYPE_ETHERTYPE, false },\n+\t{ pattern_eth_ipv4, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, false },\n+\t{ pattern_eth_ipv4_udp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, false },\n+\t{ pattern_eth_ipv4_tcp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, false },\n+\t{ pattern_eth_ipv4_any, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, false },\n+\t{ pattern_eth_ipv4_udp_vxlan, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, true },\n+\t{ pattern_eth_ipv4_udp_vxlan_udp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, true },\n+\t{ pattern_eth_ipv4_udp_vxlan_tcp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, true },\n+\t{ pattern_eth_ipv4_udp_vxlan_any, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, true },\n+\t{ pattern_eth_ipv4_udp_vxlan_eth_ipv4, SSSNIC_ETHDEV_FLOW_TYPE_FDIR,\n+\t\ttrue },\n+\t{ pattern_eth_ipv4_udp_vxlan_eth_ipv4_tcp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR,\n+\t\ttrue },\n+\t{ pattern_eth_ipv4_udp_vxlan_eth_ipv4_udp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR,\n+\t\ttrue },\n+\t{ pattern_eth_ipv4_udp_vxlan_eth_ipv6, SSSNIC_ETHDEV_FLOW_TYPE_FDIR,\n+\t\ttrue },\n+\t{ pattern_eth_ipv4_udp_vxlan_eth_ipv6_tcp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR,\n+\t\ttrue },\n+\t{ pattern_eth_ipv4_udp_vxlan_eth_ipv6_udp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR,\n+\t\ttrue },\n+\t{ pattern_eth_ipv6, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, false },\n+\t{ pattern_eth_ipv6_udp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, false },\n+\t{ pattern_eth_ipv6_tcp, SSSNIC_ETHDEV_FLOW_TYPE_FDIR, false },\n+};\n+\n+static bool\n+sssnic_ethdev_flow_pattern_match(enum rte_flow_item_type *item_array,\n+\tconst struct rte_flow_item *pattern)\n+{\n+\tconst struct rte_flow_item *item = pattern;\n+\n+\t/* skip void items in the head of pattern */\n+\twhile (item->type == RTE_FLOW_ITEM_TYPE_VOID)\n+\t\titem++;\n+\n+\twhile ((*item_array == item->type) &&\n+\t\t(*item_array != RTE_FLOW_ITEM_TYPE_END)) {\n+\t\titem_array++;\n+\t\titem++;\n+\t}\n+\n+\treturn (*item_array == RTE_FLOW_ITEM_TYPE_END &&\n+\t\titem->type == RTE_FLOW_ITEM_TYPE_END);\n+}\n+\n+static struct sssnic_ethdev_flow_pattern *\n+sssnic_ethdev_flow_pattern_lookup(const struct rte_flow_item *pattern)\n+{\n+\tstruct sssnic_ethdev_flow_pattern *flow_pattern;\n+\tenum rte_flow_item_type *flow_items;\n+\tsize_t i;\n+\n+\tfor (i = 0; i < RTE_DIM(supported_flow_patterns); i++) {\n+\t\tflow_pattern = &supported_flow_patterns[i];\n+\t\tflow_items = flow_pattern->flow_items;\n+\t\tif (sssnic_ethdev_flow_pattern_match(flow_items, pattern))\n+\t\t\treturn flow_pattern;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static int\n+sssnic_ethdev_flow_action_parse(struct rte_eth_dev *ethdev,\n+\tconst struct rte_flow_action *actions, struct rte_flow_error *error,\n+\tstruct sssnic_ethdev_fdir_rule *fdir_rule)\n+{\n+\tconst struct rte_flow_action_queue *action_queue;\n+\tconst struct rte_flow_action *action = actions;\n+\n+\tif (action->type != RTE_FLOW_ACTION_TYPE_QUEUE) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\tNULL,\n+\t\t\t\"Unsupported action type, only support action queue\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\taction_queue = (const struct rte_flow_action_queue *)action->conf;\n+\tif (action_queue->index >= ethdev->data->nb_rx_queues) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\tNULL, \"Invalid queue index\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (fdir_rule != NULL)\n+\t\tfdir_rule->action.qid = action_queue->index;\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_ethertype_pattern_parse(const struct rte_flow_item *pattern,\n+\tstruct rte_flow_error *error, struct sssnic_ethdev_fdir_rule *fdir_rule)\n+{\n+\tconst struct rte_flow_item *item = pattern;\n+\tconst struct rte_flow_item_eth *spec, *mask;\n+\tstruct sssnic_ethdev_fdir_ethertype_match *fdir_match;\n+\n+\twhile (item->type != RTE_FLOW_ITEM_TYPE_ETH)\n+\t\titem++;\n+\n+\tspec = (const struct rte_flow_item_eth *)item->spec;\n+\tmask = (const struct rte_flow_item_eth *)item->mask;\n+\n+\tif (item->last != NULL) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_LAST,\n+\t\t\titem, \"Not support range\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (spec == NULL || mask == NULL) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_LAST,\n+\t\t\titem, \"Ether mask or spec is NULL\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (!rte_is_zero_ether_addr(&mask->src) ||\n+\t\t!rte_is_zero_ether_addr(&mask->dst)) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\titem, \"Invalid ether address mask\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (mask->type != 0xffff) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_MASK,\n+\t\t\titem, \"Invalid ether type mask\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (fdir_rule != NULL) {\n+\t\tfdir_rule->match.type = SSSNIC_ETHDEV_FDIR_MATCH_ETHERTYPE;\n+\t\tfdir_match = &fdir_rule->match.ethertype;\n+\t\tfdir_match->key.ether_type = rte_be_to_cpu_16(spec->type);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_eth_parse(const struct rte_flow_item *item,\n+\tstruct rte_flow_error *error)\n+{\n+\tif (item->spec != NULL || item->mask != NULL) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\titem, \"Not support eth match in fdir flow\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_ipv4_parse(const struct rte_flow_item *item,\n+\tstruct rte_flow_error *error, bool outer,\n+\tstruct sssnic_ethdev_fdir_flow_match *fdir_match)\n+{\n+\tconst struct rte_flow_item_ipv4 *spec, *mask;\n+\tuint32_t ip_addr;\n+\n+\tspec = (const struct rte_flow_item_ipv4 *)item->spec;\n+\tmask = (const struct rte_flow_item_ipv4 *)item->mask;\n+\n+\tif (outer) {\n+\t\t/* only tunnel flow has outer ipv4 */\n+\t\tif (spec == NULL && mask == NULL)\n+\t\t\treturn 0;\n+\n+\t\tif (spec == NULL || mask == NULL) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Invalid IPV4 spec or mask\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tif (mask->hdr.version_ihl || mask->hdr.type_of_service ||\n+\t\t\tmask->hdr.total_length || mask->hdr.packet_id ||\n+\t\t\tmask->hdr.fragment_offset || mask->hdr.time_to_live ||\n+\t\t\tmask->hdr.next_proto_id || mask->hdr.hdr_checksum) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Only support outer IPv4 src and dest address for tunnel flow\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tif (fdir_match != NULL) {\n+\t\t\tip_addr = rte_be_to_cpu_32(spec->hdr.src_addr);\n+\t\t\tfdir_match->key.ipv4.outer_sip_w0 = (uint16_t)ip_addr;\n+\t\t\tfdir_match->key.ipv4.outer_sip_w1 =\n+\t\t\t\t(uint16_t)(ip_addr >> 16);\n+\n+\t\t\tip_addr = rte_be_to_cpu_32(mask->hdr.src_addr);\n+\t\t\tfdir_match->mask.ipv4.outer_sip_w0 = (uint16_t)ip_addr;\n+\t\t\tfdir_match->mask.ipv4.outer_sip_w1 =\n+\t\t\t\t(uint16_t)(ip_addr >> 16);\n+\t\t}\n+\t} else {\n+\t\t/* inner ip of tunnel flow or ip of non tunnel flow */\n+\t\tif (spec == NULL && mask == NULL)\n+\t\t\treturn 0;\n+\n+\t\tif (spec == NULL || mask == NULL) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Invalid IPV4 spec or mask\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tif (mask->hdr.version_ihl || mask->hdr.type_of_service ||\n+\t\t\tmask->hdr.total_length || mask->hdr.packet_id ||\n+\t\t\tmask->hdr.fragment_offset || mask->hdr.time_to_live ||\n+\t\t\tmask->hdr.hdr_checksum) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Only support IPv4 address and ipproto\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tif (fdir_match != NULL) {\n+\t\t\tip_addr = rte_be_to_cpu_32(spec->hdr.src_addr);\n+\t\t\tfdir_match->key.ipv4.sip_w0 = (uint16_t)ip_addr;\n+\t\t\tfdir_match->key.ipv4.sip_w1 = (uint16_t)(ip_addr >> 16);\n+\n+\t\t\tip_addr = rte_be_to_cpu_32(mask->hdr.src_addr);\n+\t\t\tfdir_match->mask.ipv4.sip_w0 = (uint16_t)ip_addr;\n+\t\t\tfdir_match->mask.ipv4.sip_w1 =\n+\t\t\t\t(uint16_t)(ip_addr >> 16);\n+\n+\t\t\tfdir_match->key.ipv4.ip_proto = spec->hdr.next_proto_id;\n+\t\t\tfdir_match->mask.ipv4.ip_proto =\n+\t\t\t\tmask->hdr.next_proto_id;\n+\n+\t\t\tfdir_match->key.ipv4.ip_type =\n+\t\t\t\tSSSNIC_ETHDEV_FDIR_FLOW_IPV4;\n+\t\t\tfdir_match->mask.ipv4.ip_type = 0x1;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_ipv6_parse(const struct rte_flow_item *item,\n+\tstruct rte_flow_error *error, bool is_tunnel,\n+\tstruct sssnic_ethdev_fdir_flow_match *fdir_match)\n+{\n+\tconst struct rte_flow_item_ipv6 *spec, *mask;\n+\tuint32_t ipv6_addr[4];\n+\tint i;\n+\n+\tmask = (const struct rte_flow_item_ipv6 *)item->mask;\n+\tspec = (const struct rte_flow_item_ipv6 *)item->spec;\n+\n+\tif (fdir_match != NULL) {\n+\t\t/* ip_type of ipv6 flow_match can share with other flow_matches */\n+\t\tfdir_match->key.ipv6.ip_type = SSSNIC_ETHDEV_FDIR_FLOW_IPV6;\n+\t\tfdir_match->mask.ipv6.ip_type = 0x1;\n+\t}\n+\n+\tif (is_tunnel) {\n+\t\tif (mask == NULL && spec == NULL)\n+\t\t\treturn 0;\n+\n+\t\tif (spec == NULL || mask == NULL) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Invalid IPV6 spec or mask\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tif (mask->hdr.vtc_flow || mask->hdr.payload_len ||\n+\t\t\tmask->hdr.hop_limits ||\n+\t\t\t!sssnic_is_zero_ipv6_addr(mask->hdr.src_addr)) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Only support IPv6 dest_addr and ipproto in tunnel flow\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tif (fdir_match != NULL) {\n+\t\t\trte_memcpy(ipv6_addr, spec->hdr.dst_addr,\n+\t\t\t\tsizeof(ipv6_addr));\n+\t\t\tfor (i = 0; i < 4; i++)\n+\t\t\t\tipv6_addr[i] = rte_be_to_cpu_32(ipv6_addr[i]);\n+\n+\t\t\tfdir_match->key.vxlan_ipv6.dip6_w0 =\n+\t\t\t\t(uint16_t)ipv6_addr[0];\n+\t\t\tfdir_match->key.vxlan_ipv6.dip6_w1 =\n+\t\t\t\t(uint16_t)(ipv6_addr[0] >> 16);\n+\t\t\tfdir_match->key.vxlan_ipv6.dip6_w2 =\n+\t\t\t\t(uint16_t)ipv6_addr[1];\n+\t\t\tfdir_match->key.vxlan_ipv6.dip6_w3 =\n+\t\t\t\t(uint16_t)(ipv6_addr[1] >> 16);\n+\t\t\tfdir_match->key.vxlan_ipv6.dip6_w4 =\n+\t\t\t\t(uint16_t)ipv6_addr[2];\n+\t\t\tfdir_match->key.vxlan_ipv6.dip6_w5 =\n+\t\t\t\t(uint16_t)(ipv6_addr[2] >> 16);\n+\t\t\tfdir_match->key.vxlan_ipv6.dip6_w6 =\n+\t\t\t\t(uint16_t)ipv6_addr[3];\n+\t\t\tfdir_match->key.vxlan_ipv6.dip6_w7 =\n+\t\t\t\t(uint16_t)(ipv6_addr[3] >> 16);\n+\n+\t\t\trte_memcpy(ipv6_addr, mask->hdr.dst_addr,\n+\t\t\t\tsizeof(ipv6_addr));\n+\t\t\tfor (i = 0; i < 4; i++)\n+\t\t\t\tipv6_addr[i] = rte_be_to_cpu_32(ipv6_addr[i]);\n+\n+\t\t\tfdir_match->mask.vxlan_ipv6.dip6_w0 =\n+\t\t\t\t(uint16_t)ipv6_addr[0];\n+\t\t\tfdir_match->mask.vxlan_ipv6.dip6_w1 =\n+\t\t\t\t(uint16_t)(ipv6_addr[0] >> 16);\n+\t\t\tfdir_match->mask.vxlan_ipv6.dip6_w2 =\n+\t\t\t\t(uint16_t)ipv6_addr[1];\n+\t\t\tfdir_match->mask.vxlan_ipv6.dip6_w3 =\n+\t\t\t\t(uint16_t)(ipv6_addr[1] >> 16);\n+\t\t\tfdir_match->mask.vxlan_ipv6.dip6_w4 =\n+\t\t\t\t(uint16_t)ipv6_addr[2];\n+\t\t\tfdir_match->mask.vxlan_ipv6.dip6_w5 =\n+\t\t\t\t(uint16_t)(ipv6_addr[2] >> 16);\n+\t\t\tfdir_match->mask.vxlan_ipv6.dip6_w6 =\n+\t\t\t\t(uint16_t)ipv6_addr[3];\n+\t\t\tfdir_match->mask.vxlan_ipv6.dip6_w7 =\n+\t\t\t\t(uint16_t)(ipv6_addr[3] >> 16);\n+\n+\t\t\tfdir_match->key.vxlan_ipv6.ip_proto = spec->hdr.proto;\n+\t\t\tfdir_match->mask.vxlan_ipv6.ip_proto = mask->hdr.proto;\n+\t\t}\n+\t} else { /* non tunnel */\n+\t\tif (spec == NULL || mask == NULL) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Invalid IPV6 spec or mask\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tif (mask->hdr.vtc_flow || mask->hdr.payload_len ||\n+\t\t\tmask->hdr.hop_limits) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Only support IPv6 addr and ipproto\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tif (fdir_match != NULL) {\n+\t\t\trte_memcpy(ipv6_addr, spec->hdr.dst_addr,\n+\t\t\t\tsizeof(ipv6_addr));\n+\t\t\tfor (i = 0; i < 4; i++)\n+\t\t\t\tipv6_addr[i] = rte_be_to_cpu_32(ipv6_addr[i]);\n+\n+\t\t\tfdir_match->key.ipv6.dip6_w0 = (uint16_t)ipv6_addr[0];\n+\t\t\tfdir_match->key.ipv6.dip6_w1 =\n+\t\t\t\t(uint16_t)(ipv6_addr[0] >> 16);\n+\t\t\tfdir_match->key.ipv6.dip6_w2 = (uint16_t)ipv6_addr[1];\n+\t\t\tfdir_match->key.ipv6.dip6_w3 =\n+\t\t\t\t(uint16_t)(ipv6_addr[1] >> 16);\n+\t\t\tfdir_match->key.ipv6.dip6_w4 = (uint16_t)ipv6_addr[2];\n+\t\t\tfdir_match->key.ipv6.dip6_w5 =\n+\t\t\t\t(uint16_t)(ipv6_addr[2] >> 16);\n+\t\t\tfdir_match->key.ipv6.dip6_w6 = (uint16_t)ipv6_addr[3];\n+\t\t\tfdir_match->key.ipv6.dip6_w7 =\n+\t\t\t\t(uint16_t)(ipv6_addr[3] >> 16);\n+\n+\t\t\trte_memcpy(ipv6_addr, spec->hdr.src_addr,\n+\t\t\t\tsizeof(ipv6_addr));\n+\t\t\tfor (i = 0; i < 4; i++)\n+\t\t\t\tipv6_addr[i] = rte_be_to_cpu_32(ipv6_addr[i]);\n+\n+\t\t\tfdir_match->key.ipv6.sip6_w0 = (uint16_t)ipv6_addr[0];\n+\t\t\tfdir_match->key.ipv6.sip6_w1 =\n+\t\t\t\t(uint16_t)(ipv6_addr[0] >> 16);\n+\t\t\tfdir_match->key.ipv6.sip6_w2 = (uint16_t)ipv6_addr[1];\n+\t\t\tfdir_match->key.ipv6.sip6_w3 =\n+\t\t\t\t(uint16_t)(ipv6_addr[1] >> 16);\n+\t\t\tfdir_match->key.ipv6.sip6_w4 = (uint16_t)ipv6_addr[2];\n+\t\t\tfdir_match->key.ipv6.sip6_w5 =\n+\t\t\t\t(uint16_t)(ipv6_addr[2] >> 16);\n+\t\t\tfdir_match->key.ipv6.sip6_w6 = (uint16_t)ipv6_addr[3];\n+\t\t\tfdir_match->key.ipv6.sip6_w7 =\n+\t\t\t\t(uint16_t)(ipv6_addr[3] >> 16);\n+\n+\t\t\trte_memcpy(ipv6_addr, mask->hdr.dst_addr,\n+\t\t\t\tsizeof(ipv6_addr));\n+\t\t\tfor (i = 0; i < 4; i++)\n+\t\t\t\tipv6_addr[i] = rte_be_to_cpu_32(ipv6_addr[i]);\n+\n+\t\t\tfdir_match->mask.ipv6.dip6_w0 = (uint16_t)ipv6_addr[0];\n+\t\t\tfdir_match->mask.ipv6.dip6_w1 =\n+\t\t\t\t(uint16_t)(ipv6_addr[0] >> 16);\n+\t\t\tfdir_match->mask.ipv6.dip6_w2 = (uint16_t)ipv6_addr[1];\n+\t\t\tfdir_match->mask.ipv6.dip6_w3 =\n+\t\t\t\t(uint16_t)(ipv6_addr[1] >> 16);\n+\t\t\tfdir_match->mask.ipv6.dip6_w4 = (uint16_t)ipv6_addr[2];\n+\t\t\tfdir_match->mask.ipv6.dip6_w5 =\n+\t\t\t\t(uint16_t)(ipv6_addr[2] >> 16);\n+\t\t\tfdir_match->mask.ipv6.dip6_w6 = (uint16_t)ipv6_addr[3];\n+\t\t\tfdir_match->mask.ipv6.dip6_w7 =\n+\t\t\t\t(uint16_t)(ipv6_addr[3] >> 16);\n+\n+\t\t\trte_memcpy(ipv6_addr, mask->hdr.src_addr,\n+\t\t\t\tsizeof(ipv6_addr));\n+\t\t\tfor (i = 0; i < 4; i++)\n+\t\t\t\tipv6_addr[i] = rte_be_to_cpu_32(ipv6_addr[i]);\n+\n+\t\t\tfdir_match->mask.ipv6.sip6_w0 = (uint16_t)ipv6_addr[0];\n+\t\t\tfdir_match->mask.ipv6.sip6_w1 =\n+\t\t\t\t(uint16_t)(ipv6_addr[0] >> 16);\n+\t\t\tfdir_match->mask.ipv6.sip6_w2 = (uint16_t)ipv6_addr[1];\n+\t\t\tfdir_match->mask.ipv6.sip6_w3 =\n+\t\t\t\t(uint16_t)(ipv6_addr[1] >> 16);\n+\t\t\tfdir_match->mask.ipv6.sip6_w4 = (uint16_t)ipv6_addr[2];\n+\t\t\tfdir_match->mask.ipv6.sip6_w5 =\n+\t\t\t\t(uint16_t)(ipv6_addr[2] >> 16);\n+\t\t\tfdir_match->mask.ipv6.sip6_w6 = (uint16_t)ipv6_addr[3];\n+\t\t\tfdir_match->mask.ipv6.sip6_w7 =\n+\t\t\t\t(uint16_t)(ipv6_addr[3] >> 16);\n+\n+\t\t\tfdir_match->key.ipv6.ip_proto = spec->hdr.proto;\n+\t\t\tfdir_match->mask.ipv6.ip_proto = mask->hdr.proto;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_udp_parse(const struct rte_flow_item *item,\n+\tstruct rte_flow_error *error, bool outer,\n+\tstruct sssnic_ethdev_fdir_flow_match *fdir_match)\n+{\n+\tconst struct rte_flow_item_udp *spec, *mask;\n+\n+\tspec = (const struct rte_flow_item_udp *)item->spec;\n+\tmask = (const struct rte_flow_item_udp *)item->mask;\n+\n+\tif (outer) {\n+\t\tif (spec != NULL || mask != NULL) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Both of outer UDP spec and mask must be NULL in tunnel flow\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (fdir_match != NULL) {\n+\t\t/* ipv6 match can share ip_proto with ipv4 match */\n+\t\tfdir_match->key.ipv4.ip_proto = IPPROTO_UDP;\n+\t\tfdir_match->mask.ipv4.ip_proto = 0xff;\n+\t}\n+\n+\tif (spec == NULL && mask == NULL)\n+\t\treturn 0;\n+\n+\tif (spec == NULL || mask == NULL) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\titem, \"Invalid UDP spec or mask\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (fdir_match != NULL) {\n+\t\t/* Other types of fdir match can share sport and dport with ipv4 match */\n+\t\tfdir_match->key.ipv4.sport =\n+\t\t\trte_be_to_cpu_16(spec->hdr.src_port);\n+\t\tfdir_match->mask.ipv4.sport =\n+\t\t\trte_be_to_cpu_16(mask->hdr.src_port);\n+\t\tfdir_match->key.ipv4.dport =\n+\t\t\trte_be_to_cpu_16(spec->hdr.dst_port);\n+\t\tfdir_match->mask.ipv4.dport =\n+\t\t\trte_be_to_cpu_16(mask->hdr.dst_port);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_tcp_parse(const struct rte_flow_item *item,\n+\tstruct rte_flow_error *error, bool outer,\n+\tstruct sssnic_ethdev_fdir_flow_match *fdir_match)\n+{\n+\tconst struct rte_flow_item_tcp *spec, *mask;\n+\n+\tspec = (const struct rte_flow_item_tcp *)item->spec;\n+\tmask = (const struct rte_flow_item_tcp *)item->mask;\n+\n+\tif (outer) {\n+\t\tif (spec != NULL || mask != NULL) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t\"Both of outer TCP spec and mask must be NULL in tunnel flow\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (fdir_match != NULL) {\n+\t\t/* ipv6 match can share ip_proto with ipv4 match */\n+\t\tfdir_match->key.ipv4.ip_proto = IPPROTO_TCP;\n+\t\tfdir_match->mask.ipv6.ip_proto = 0xff;\n+\t}\n+\n+\tif (spec == NULL && mask == NULL)\n+\t\treturn 0;\n+\n+\tif (spec == NULL || mask == NULL) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\titem, \"Invalid TCP spec or mask.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (mask->hdr.sent_seq || mask->hdr.recv_ack || mask->hdr.data_off ||\n+\t\tmask->hdr.rx_win || mask->hdr.tcp_flags || mask->hdr.cksum ||\n+\t\tmask->hdr.tcp_urp) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\titem,\n+\t\t\t\"Invalid TCP item, support src_port and dst_port only\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (fdir_match != NULL) {\n+\t\t/* Other types of fdir match can share sport and dport with ipv4 match */\n+\t\tfdir_match->key.ipv4.sport =\n+\t\t\trte_be_to_cpu_16(spec->hdr.src_port);\n+\t\tfdir_match->mask.ipv4.sport =\n+\t\t\trte_be_to_cpu_16(mask->hdr.src_port);\n+\t\tfdir_match->key.ipv4.dport =\n+\t\t\trte_be_to_cpu_16(spec->hdr.dst_port);\n+\t\tfdir_match->mask.ipv4.dport =\n+\t\t\trte_be_to_cpu_16(mask->hdr.dst_port);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_vxlan_parse(const struct rte_flow_item *item,\n+\tstruct rte_flow_error *error,\n+\tstruct sssnic_ethdev_fdir_flow_match *fdir_match)\n+{\n+\tconst struct rte_flow_item_vxlan *spec, *mask;\n+\tuint32_t vni;\n+\n+\tspec = (const struct rte_flow_item_vxlan *)item->spec;\n+\tmask = (const struct rte_flow_item_vxlan *)item->mask;\n+\n+\tif (spec == NULL && mask == NULL)\n+\t\treturn 0;\n+\n+\tif (spec == NULL || mask == NULL) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\titem, \"Invalid VXLAN spec or mask\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\t/* vxlan-ipv6 match can share vni with vxlan-ipv4 match */\n+\tif (fdir_match != NULL) {\n+\t\trte_memcpy(((uint8_t *)&vni) + 1, spec->vni, 3);\n+\t\tvni = rte_be_to_cpu_32(vni);\n+\t\tfdir_match->key.ipv4.vni_w0 = (uint16_t)vni;\n+\t\tfdir_match->key.ipv4.vni_w1 = (uint16_t)(vni >> 16);\n+\t\trte_memcpy(((uint8_t *)&vni) + 1, mask->vni, 3);\n+\t\tvni = rte_be_to_cpu_32(vni);\n+\t\tfdir_match->mask.ipv4.vni_w0 = (uint16_t)vni;\n+\t\tfdir_match->mask.ipv4.vni_w1 = (uint16_t)(vni >> 16);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_fdir_pattern_parse(const struct rte_flow_item *pattern,\n+\tstruct rte_flow_error *error, bool is_tunnel,\n+\tstruct sssnic_ethdev_fdir_rule *fdir_rule)\n+{\n+\tstruct sssnic_ethdev_fdir_flow_match *fdir_match = NULL;\n+\tconst struct rte_flow_item *flow_item;\n+\tbool outer_ip;\n+\tint ret = 0;\n+\n+\tfdir_rule->match.type = SSSNIC_ETHDEV_FDIR_MATCH_FLOW;\n+\tif (fdir_rule != NULL)\n+\t\tfdir_match = &fdir_rule->match.flow;\n+\n+\tif (is_tunnel)\n+\t\touter_ip = true;\n+\telse\n+\t\touter_ip = false;\n+\n+\tflow_item = pattern;\n+\twhile (flow_item->type != RTE_FLOW_ITEM_TYPE_END) {\n+\t\tswitch (flow_item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\tret = sssnic_ethdev_flow_eth_parse(flow_item, error);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tret = sssnic_ethdev_flow_ipv4_parse(flow_item, error,\n+\t\t\t\touter_ip, fdir_match);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n+\t\t\tret = sssnic_ethdev_flow_ipv6_parse(flow_item, error,\n+\t\t\t\tis_tunnel, fdir_match);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tret = sssnic_ethdev_flow_udp_parse(flow_item, error,\n+\t\t\t\touter_ip, fdir_match);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\t\tret = sssnic_ethdev_flow_tcp_parse(flow_item, error,\n+\t\t\t\touter_ip, fdir_match);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\t\tret = sssnic_ethdev_flow_vxlan_parse(flow_item, error,\n+\t\t\t\tfdir_match);\n+\t\t\touter_ip = false; /* next parsing is inner_ip */\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (ret != 0)\n+\t\t\treturn ret;\n+\n+\t\tflow_item++;\n+\t}\n+\n+\tif (is_tunnel) {\n+\t\tif (fdir_match != NULL) {\n+\t\t\t/* tunnel_type of ipv4 flow_match can share with other flow_matches */\n+\t\t\tfdir_match->key.ipv4.tunnel_type =\n+\t\t\t\tSSSNIC_ETHDEV_FDIR_FLOW_TUNNEL_VXLAN;\n+\t\t\tfdir_match->mask.ipv4.tunnel_type = 0x1;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_attr_parse(const struct rte_flow_attr *attr,\n+\tstruct rte_flow_error *error)\n+{\n+\tif (attr->egress != 0 || attr->priority != 0 || attr->group != 0) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR,\n+\t\t\tattr, \"Invalid flow attr, support ingress only\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (attr->ingress == 0) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ATTR_INGRESS, attr,\n+\t\t\t\"Ingress of flow attr is not set\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_parse(struct rte_eth_dev *ethdev,\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+\tstruct sssnic_ethdev_fdir_rule *fdir_rule)\n+{\n+\tint ret;\n+\tstruct sssnic_ethdev_flow_pattern *flow_pattern;\n+\n+\tflow_pattern = sssnic_ethdev_flow_pattern_lookup(pattern);\n+\tif (flow_pattern == NULL) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\tNULL, \"Unsupported pattern\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (flow_pattern->type == SSSNIC_ETHDEV_FLOW_TYPE_FDIR)\n+\t\tret = sssnic_ethdev_flow_fdir_pattern_parse(pattern, error,\n+\t\t\tflow_pattern->is_tunnel, fdir_rule);\n+\telse\n+\t\tret = sssnic_ethdev_flow_ethertype_pattern_parse(pattern, error,\n+\t\t\tfdir_rule);\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\tret = sssnic_ethdev_flow_action_parse(ethdev, actions, error,\n+\t\tfdir_rule);\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\tret = sssnic_ethdev_flow_attr_parse(attr, error);\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+\n+static struct rte_flow *\n+sssnic_ethdev_flow_create(struct rte_eth_dev *ethdev,\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 sssnic_ethdev_fdir_rule *rule;\n+\tint ret;\n+\n+\trule = sssnic_ethdev_fdir_rule_alloc();\n+\tif (rule == NULL) {\n+\t\trte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,\n+\t\t\tNULL, \"Failed to allocate fdir rule memory\");\n+\t\treturn NULL;\n+\t}\n+\n+\tret = sssnic_ethdev_flow_parse(ethdev, attr, pattern, actions, error,\n+\t\trule);\n+\tif (ret != 0) {\n+\t\tsssnic_ethdev_fdir_rule_free(rule);\n+\t\treturn NULL;\n+\t}\n+\n+\tret = sssnic_ethdev_fdir_rule_add(ethdev, rule);\n+\tif (ret != 0) {\n+\t\tsssnic_ethdev_fdir_rule_free(rule);\n+\t\trte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\"Failed to add fdir rule\");\n+\t\treturn NULL;\n+\t}\n+\n+\treturn (struct rte_flow *)rule;\n+}\n+\n+static int\n+sssnic_ethdev_flow_destroy(struct rte_eth_dev *ethdev, struct rte_flow *flow,\n+\tstruct rte_flow_error *error)\n+{\n+\tint ret;\n+\n+\tif (flow == NULL) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE,\n+\t\t\tNULL, \"Invalid parameter\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tret = sssnic_ethdev_fdir_rule_del(ethdev,\n+\t\t(struct sssnic_ethdev_fdir_rule *)flow);\n+\n+\tif (ret != 0) {\n+\t\trte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\"Failed to delete fdir rule\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tsssnic_ethdev_fdir_rule_free((struct sssnic_ethdev_fdir_rule *)flow);\n+\n+\treturn 0;\n+}\n+\n+static int\n+sssnic_ethdev_flow_validate(struct rte_eth_dev *ethdev,\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+\treturn sssnic_ethdev_flow_parse(ethdev, attr, pattern, actions, error,\n+\t\tNULL);\n+}\n+\n+static int\n+sssnic_ethdev_flow_flush(struct rte_eth_dev *ethdev,\n+\tstruct rte_flow_error *error)\n+{\n+\tint ret;\n+\n+\tret = sssnic_ethdev_fdir_rules_flush(ethdev);\n+\tif (ret != 0) {\n+\t\trte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\"Failed to flush fdir rules\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static const struct rte_flow_ops sssnic_ethdev_flow_ops = {\n+\t.validate = sssnic_ethdev_flow_validate,\n+\t.create = sssnic_ethdev_flow_create,\n+\t.destroy = sssnic_ethdev_flow_destroy,\n+\t.flush = sssnic_ethdev_flow_flush,\n+};\n+\n+int\n+sssnic_ethdev_flow_ops_get(struct rte_eth_dev *ethdev,\n+\tconst struct rte_flow_ops **ops)\n+{\n+\tRTE_SET_USED(ethdev);\n+\n+\t*ops = &sssnic_ethdev_flow_ops;\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/net/sssnic/sssnic_ethdev_flow.h b/drivers/net/sssnic/sssnic_ethdev_flow.h\nnew file mode 100644\nindex 0000000000..2812b783e2\n--- /dev/null\n+++ b/drivers/net/sssnic/sssnic_ethdev_flow.h\n@@ -0,0 +1,11 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd.\n+ */\n+\n+#ifndef _SSSNIC_ETHDEV_FLOW_H_\n+#define _SSSNIC_ETHDEV_FLOW_H_\n+\n+int sssnic_ethdev_flow_ops_get(struct rte_eth_dev *ethdev,\n+\tconst struct rte_flow_ops **ops);\n+\n+#endif /* _SSSNIC_ETHDEV_FLOW_H_ */\ndiff --git a/drivers/net/sssnic/sssnic_ethdev_rx.c b/drivers/net/sssnic/sssnic_ethdev_rx.c\nindex 6c5f209262..46a1d5fd23 100644\n--- a/drivers/net/sssnic/sssnic_ethdev_rx.c\n+++ b/drivers/net/sssnic/sssnic_ethdev_rx.c\n@@ -11,6 +11,7 @@\n #include \"sssnic_ethdev.h\"\n #include \"sssnic_ethdev_rx.h\"\n #include \"sssnic_ethdev_rss.h\"\n+#include \"sssnic_ethdev_fdir.h\"\n #include \"base/sssnic_hw.h\"\n #include \"base/sssnic_workq.h\"\n #include \"base/sssnic_api.h\"\n@@ -593,9 +594,18 @@ static int\n sssnic_ethdev_rxq_enable(struct rte_eth_dev *ethdev, uint16_t queue_id)\n {\n \tstruct sssnic_ethdev_rxq *rxq = ethdev->data->rx_queues[queue_id];\n+\tint ret;\n \n \tsssnic_ethdev_rxq_pktmbufs_fill(rxq);\n \n+\tpthread_mutex_lock(&ethdev->data->flow_ops_mutex);\n+\tret = sssnic_ethdev_fdir_rules_enable_by_queue(ethdev, queue_id);\n+\tif (ret)\n+\t\tPMD_DRV_LOG(WARNING,\n+\t\t\t\"Failed to enable fdir rules of rxq:%u, port:%u\",\n+\t\t\tqueue_id, ethdev->data->port_id);\n+\tpthread_mutex_unlock(&ethdev->data->flow_ops_mutex);\n+\n \treturn 0;\n }\n \n@@ -605,6 +615,14 @@ sssnic_ethdev_rxq_disable(struct rte_eth_dev *ethdev, uint16_t queue_id)\n \tstruct sssnic_ethdev_rxq *rxq = ethdev->data->rx_queues[queue_id];\n \tint ret;\n \n+\tpthread_mutex_lock(&ethdev->data->flow_ops_mutex);\n+\tret = sssnic_ethdev_fdir_rules_disable_by_queue(ethdev, queue_id);\n+\tif (ret != 0)\n+\t\tPMD_DRV_LOG(WARNING,\n+\t\t\t\"Failed to disable fdir rules of rxq:%u, port:%u\",\n+\t\t\tqueue_id, ethdev->data->port_id);\n+\tpthread_mutex_unlock(&ethdev->data->flow_ops_mutex);\n+\n \tret = sssnic_ethdev_rxq_flush(rxq);\n \tif (ret != 0) {\n \t\tPMD_DRV_LOG(ERR, \"Failed to flush rxq:%u, port:%u\", queue_id,\n",
    "prefixes": [
        "v3",
        "31/32"
    ]
}