get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 29364,
    "url": "https://patches.dpdk.org/api/patches/29364/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20170928141329.73874-19-ajit.khaparde@broadcom.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": "<20170928141329.73874-19-ajit.khaparde@broadcom.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20170928141329.73874-19-ajit.khaparde@broadcom.com",
    "date": "2017-09-28T14:13:23",
    "name": "[dpdk-dev,v3,18/24] net/bnxt: add support for flow filter ops",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": true,
    "hash": "a37a02f9eb1ecf1c02075ed3377bf3f742cec0be",
    "submitter": {
        "id": 501,
        "url": "https://patches.dpdk.org/api/people/501/?format=api",
        "name": "Ajit Khaparde",
        "email": "ajit.khaparde@broadcom.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/20170928141329.73874-19-ajit.khaparde@broadcom.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/29364/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/29364/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id C04881B28E;\n\tThu, 28 Sep 2017 16:14:27 +0200 (CEST)",
            "from rnd-relay.smtp.broadcom.com (lpdvrndsmtp01.broadcom.com\n\t[192.19.229.170]) by dpdk.org (Postfix) with ESMTP id A394D1B248\n\tfor <dev@dpdk.org>; Thu, 28 Sep 2017 16:14:06 +0200 (CEST)",
            "from mail-irv-17.broadcom.com (mail-irv-17.lvn.broadcom.net\n\t[10.75.224.233])\n\tby rnd-relay.smtp.broadcom.com (Postfix) with ESMTP id AEC8C30C01D;\n\tThu, 28 Sep 2017 07:14:05 -0700 (PDT)",
            "from C02PT1RBG8WP.vpn.broadcom.net (unknown [10.10.116.190])\n\tby mail-irv-17.broadcom.com (Postfix) with ESMTP id 19F0081EB3;\n\tThu, 28 Sep 2017 07:13:50 -0700 (PDT)"
        ],
        "From": "Ajit Khaparde <ajit.khaparde@broadcom.com>",
        "To": "dev@dpdk.org",
        "Cc": "ferruh.yigit@intel.com",
        "Date": "Thu, 28 Sep 2017 09:13:23 -0500",
        "Message-Id": "<20170928141329.73874-19-ajit.khaparde@broadcom.com>",
        "X-Mailer": "git-send-email 2.13.5 (Apple Git-94)",
        "In-Reply-To": "<20170928141329.73874-1-ajit.khaparde@broadcom.com>",
        "References": "<20170928141329.73874-1-ajit.khaparde@broadcom.com>",
        "Subject": "[dpdk-dev] [PATCH v3 18/24] net/bnxt: add support for flow filter\n\tops",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch adds support for flow validate/create/destroy/flush,\nethertype add/del ops\n\nSigned-off-by: Ajit Khaparde <ajit.khaparde@broadcom.com>\n--\nv1->v2: incorporate review comments.\nv2->v3: fix 32-bit builds.\n---\n drivers/net/bnxt/bnxt.h         |   7 +\n drivers/net/bnxt/bnxt_ethdev.c  | 202 +++++++++-\n drivers/net/bnxt/bnxt_filter.c  | 870 +++++++++++++++++++++++++++++++++++++++-\n drivers/net/bnxt/bnxt_filter.h  |  76 ++++\n drivers/net/bnxt/bnxt_hwrm.c    | 302 ++++++++++++--\n drivers/net/bnxt/bnxt_hwrm.h    |  12 +-\n drivers/net/bnxt/bnxt_vnic.c    |   1 +\n drivers/net/bnxt/bnxt_vnic.h    |   1 +\n drivers/net/bnxt/rte_pmd_bnxt.c |   4 +-\n 9 files changed, 1433 insertions(+), 42 deletions(-)",
    "diff": "diff --git a/drivers/net/bnxt/bnxt.h b/drivers/net/bnxt/bnxt.h\nindex 65f716b96..e7b1007c1 100644\n--- a/drivers/net/bnxt/bnxt.h\n+++ b/drivers/net/bnxt/bnxt.h\n@@ -171,6 +171,12 @@ struct bnxt_cos_queue_info {\n \tuint8_t\tprofile;\n };\n \n+struct rte_flow {\n+\tSTAILQ_ENTRY(rte_flow) next;\n+\tstruct bnxt_filter_info *filter;\n+\tstruct bnxt_vnic_info\t*vnic;\n+};\n+\n #define BNXT_HWRM_SHORT_REQ_LEN\t\tsizeof(struct hwrm_short_input)\n struct bnxt {\n \tvoid\t\t\t\t*bar0;\n@@ -271,4 +277,5 @@ int bnxt_rcv_msg_from_vf(struct bnxt *bp, uint16_t vf_id, void *msg);\n #define RX_PROD_AGG_BD_TYPE_RX_PROD_AGG\t\t0x6\n \n bool is_bnxt_supported(struct rte_eth_dev *dev);\n+extern const struct rte_flow_ops bnxt_flow_ops;\n #endif\ndiff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c\nindex 97ddca069..fdba0ac69 100644\n--- a/drivers/net/bnxt/bnxt_ethdev.c\n+++ b/drivers/net/bnxt/bnxt_ethdev.c\n@@ -616,7 +616,7 @@ static void bnxt_mac_addr_remove_op(struct rte_eth_dev *eth_dev,\n \t\t\t\tif (filter->mac_index == index) {\n \t\t\t\t\tSTAILQ_REMOVE(&vnic->filter, filter,\n \t\t\t\t\t\t      bnxt_filter_info, next);\n-\t\t\t\t\tbnxt_hwrm_clear_filter(bp, filter);\n+\t\t\t\t\tbnxt_hwrm_clear_l2_filter(bp, filter);\n \t\t\t\t\tfilter->mac_index = INVALID_MAC_INDEX;\n \t\t\t\t\tmemset(&filter->l2_addr, 0,\n \t\t\t\t\t       ETHER_ADDR_LEN);\n@@ -663,7 +663,7 @@ static int bnxt_mac_addr_add_op(struct rte_eth_dev *eth_dev,\n \tSTAILQ_INSERT_TAIL(&vnic->filter, filter, next);\n \tfilter->mac_index = index;\n \tmemcpy(filter->l2_addr, mac_addr, ETHER_ADDR_LEN);\n-\treturn bnxt_hwrm_set_filter(bp, vnic->fw_vnic_id, filter);\n+\treturn bnxt_hwrm_set_l2_filter(bp, vnic->fw_vnic_id, filter);\n }\n \n int bnxt_link_update_op(struct rte_eth_dev *eth_dev, int wait_to_complete)\n@@ -1157,7 +1157,7 @@ static int bnxt_del_vlan_filter(struct bnxt *bp, uint16_t vlan_id)\n \t\t\t\t\t/* Must delete the filter */\n \t\t\t\t\tSTAILQ_REMOVE(&vnic->filter, filter,\n \t\t\t\t\t\t      bnxt_filter_info, next);\n-\t\t\t\t\tbnxt_hwrm_clear_filter(bp, filter);\n+\t\t\t\t\tbnxt_hwrm_clear_l2_filter(bp, filter);\n \t\t\t\t\tSTAILQ_INSERT_TAIL(\n \t\t\t\t\t\t\t&bp->free_filter_list,\n \t\t\t\t\t\t\tfilter, next);\n@@ -1183,7 +1183,7 @@ static int bnxt_del_vlan_filter(struct bnxt *bp, uint16_t vlan_id)\n \t\t\t\t\tmemcpy(new_filter->l2_addr,\n \t\t\t\t\t       filter->l2_addr, ETHER_ADDR_LEN);\n \t\t\t\t\t/* MAC only filter */\n-\t\t\t\t\trc = bnxt_hwrm_set_filter(bp,\n+\t\t\t\t\trc = bnxt_hwrm_set_l2_filter(bp,\n \t\t\t\t\t\t\tvnic->fw_vnic_id,\n \t\t\t\t\t\t\tnew_filter);\n \t\t\t\t\tif (rc)\n@@ -1235,7 +1235,7 @@ static int bnxt_add_vlan_filter(struct bnxt *bp, uint16_t vlan_id)\n \t\t\t\t\t/* Must delete the MAC filter */\n \t\t\t\t\tSTAILQ_REMOVE(&vnic->filter, filter,\n \t\t\t\t\t\t      bnxt_filter_info, next);\n-\t\t\t\t\tbnxt_hwrm_clear_filter(bp, filter);\n+\t\t\t\t\tbnxt_hwrm_clear_l2_filter(bp, filter);\n \t\t\t\t\tfilter->l2_ovlan = 0;\n \t\t\t\t\tSTAILQ_INSERT_TAIL(\n \t\t\t\t\t\t\t&bp->free_filter_list,\n@@ -1258,8 +1258,9 @@ static int bnxt_add_vlan_filter(struct bnxt *bp, uint16_t vlan_id)\n \t\t\t\tnew_filter->l2_ovlan = vlan_id;\n \t\t\t\tnew_filter->l2_ovlan_mask = 0xF000;\n \t\t\t\tnew_filter->enables |= en;\n-\t\t\t\trc = bnxt_hwrm_set_filter(bp, vnic->fw_vnic_id,\n-\t\t\t\t\t\t\t  new_filter);\n+\t\t\t\trc = bnxt_hwrm_set_l2_filter(bp,\n+\t\t\t\t\t\t\t     vnic->fw_vnic_id,\n+\t\t\t\t\t\t\t     new_filter);\n \t\t\t\tif (rc)\n \t\t\t\t\tgoto exit;\n \t\t\t\tRTE_LOG(INFO, PMD,\n@@ -1338,7 +1339,7 @@ bnxt_set_default_mac_addr_op(struct rte_eth_dev *dev, struct ether_addr *addr)\n \t\t/* Default Filter is at Index 0 */\n \t\tif (filter->mac_index != 0)\n \t\t\tcontinue;\n-\t\trc = bnxt_hwrm_clear_filter(bp, filter);\n+\t\trc = bnxt_hwrm_clear_l2_filter(bp, filter);\n \t\tif (rc)\n \t\t\tbreak;\n \t\tmemcpy(filter->l2_addr, bp->mac_addr, ETHER_ADDR_LEN);\n@@ -1347,7 +1348,7 @@ bnxt_set_default_mac_addr_op(struct rte_eth_dev *dev, struct ether_addr *addr)\n \t\tfilter->enables |=\n \t\t\tHWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR |\n \t\t\tHWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR_MASK;\n-\t\trc = bnxt_hwrm_set_filter(bp, vnic->fw_vnic_id, filter);\n+\t\trc = bnxt_hwrm_set_l2_filter(bp, vnic->fw_vnic_id, filter);\n \t\tif (rc)\n \t\t\tbreak;\n \t\tfilter->mac_index = 0;\n@@ -1647,6 +1648,188 @@ bnxt_tx_descriptor_status_op(void *tx_queue, uint16_t offset)\n \treturn RTE_ETH_TX_DESC_FULL;\n }\n \n+static struct bnxt_filter_info *\n+bnxt_match_and_validate_ether_filter(struct bnxt *bp,\n+\t\t\t\tstruct rte_eth_ethertype_filter *efilter,\n+\t\t\t\tstruct bnxt_vnic_info *vnic0,\n+\t\t\t\tstruct bnxt_vnic_info *vnic,\n+\t\t\t\tint *ret)\n+{\n+\tstruct bnxt_filter_info *mfilter = NULL;\n+\tint match = 0;\n+\t*ret = 0;\n+\n+\tif (efilter->ether_type != ETHER_TYPE_IPv4 &&\n+\t\tefilter->ether_type != ETHER_TYPE_IPv6) {\n+\t\tRTE_LOG(ERR, PMD, \"unsupported ether_type(0x%04x) in\"\n+\t\t\t\" ethertype filter.\", efilter->ether_type);\n+\t\t*ret = -EINVAL;\n+\t}\n+\tif (efilter->queue >= bp->rx_nr_rings) {\n+\t\tRTE_LOG(ERR, PMD, \"Invalid queue %d\\n\", efilter->queue);\n+\t\t*ret = -EINVAL;\n+\t}\n+\n+\tvnic0 = STAILQ_FIRST(&bp->ff_pool[0]);\n+\tvnic = STAILQ_FIRST(&bp->ff_pool[efilter->queue]);\n+\tif (vnic == NULL) {\n+\t\tRTE_LOG(ERR, PMD, \"Invalid queue %d\\n\", efilter->queue);\n+\t\t*ret = -EINVAL;\n+\t}\n+\n+\tif (efilter->flags & RTE_ETHTYPE_FLAGS_DROP) {\n+\t\tSTAILQ_FOREACH(mfilter, &vnic0->filter, next) {\n+\t\t\tif ((!memcmp(efilter->mac_addr.addr_bytes,\n+\t\t\t\t     mfilter->l2_addr, ETHER_ADDR_LEN) &&\n+\t\t\t     (mfilter->flags ==\n+\t\t\t      HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_FLAGS_DROP) &&\n+\t\t\t     (mfilter->ethertype == efilter->ether_type))) {\n+\t\t\t\tmatch = 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t} else {\n+\t\tSTAILQ_FOREACH(mfilter, &vnic->filter, next)\n+\t\t\tif ((!memcmp(efilter->mac_addr.addr_bytes,\n+\t\t\t\t     mfilter->l2_addr, ETHER_ADDR_LEN) &&\n+\t\t\t     (mfilter->ethertype == efilter->ether_type) &&\n+\t\t\t     (mfilter->flags ==\n+\t\t\t      HWRM_CFA_L2_FILTER_CFG_INPUT_FLAGS_PATH_RX))) {\n+\t\t\t\tmatch = 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t}\n+\n+\tif (match)\n+\t\t*ret = -EEXIST;\n+\n+\treturn mfilter;\n+}\n+\n+static int\n+bnxt_ethertype_filter(struct rte_eth_dev *dev,\n+\t\t\tenum rte_filter_op filter_op,\n+\t\t\tvoid *arg)\n+{\n+\tstruct bnxt *bp = (struct bnxt *)dev->data->dev_private;\n+\tstruct rte_eth_ethertype_filter *efilter =\n+\t\t\t(struct rte_eth_ethertype_filter *)arg;\n+\tstruct bnxt_filter_info *bfilter, *filter1;\n+\tstruct bnxt_vnic_info *vnic, *vnic0;\n+\tint ret;\n+\n+\tif (filter_op == RTE_ETH_FILTER_NOP)\n+\t\treturn 0;\n+\n+\tif (arg == NULL) {\n+\t\tRTE_LOG(ERR, PMD, \"arg shouldn't be NULL for operation %u.\",\n+\t\t\t    filter_op);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tvnic0 = STAILQ_FIRST(&bp->ff_pool[0]);\n+\tvnic = STAILQ_FIRST(&bp->ff_pool[efilter->queue]);\n+\n+\tswitch (filter_op) {\n+\tcase RTE_ETH_FILTER_ADD:\n+\t\tbnxt_match_and_validate_ether_filter(bp, efilter,\n+\t\t\t\t\t\t\tvnic0, vnic, &ret);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\n+\t\tbfilter = bnxt_get_unused_filter(bp);\n+\t\tif (bfilter == NULL) {\n+\t\t\tRTE_LOG(ERR, PMD,\n+\t\t\t\t\"Not enough resources for a new filter.\\n\");\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\t\tbfilter->filter_type = HWRM_CFA_NTUPLE_FILTER;\n+\t\tmemcpy(bfilter->l2_addr, efilter->mac_addr.addr_bytes,\n+\t\t       ETHER_ADDR_LEN);\n+\t\tmemcpy(bfilter->dst_macaddr, efilter->mac_addr.addr_bytes,\n+\t\t       ETHER_ADDR_LEN);\n+\t\tbfilter->enables |= NTUPLE_FLTR_ALLOC_INPUT_EN_DST_MACADDR;\n+\t\tbfilter->ethertype = efilter->ether_type;\n+\t\tbfilter->enables |= NTUPLE_FLTR_ALLOC_INPUT_EN_ETHERTYPE;\n+\n+\t\tfilter1 = bnxt_get_l2_filter(bp, bfilter, vnic0);\n+\t\tif (filter1 == NULL) {\n+\t\t\tret = -1;\n+\t\t\tgoto cleanup;\n+\t\t}\n+\t\tbfilter->enables |=\n+\t\t\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_L2_FILTER_ID;\n+\t\tbfilter->fw_l2_filter_id = filter1->fw_l2_filter_id;\n+\n+\t\tbfilter->dst_id = vnic->fw_vnic_id;\n+\n+\t\tif (efilter->flags & RTE_ETHTYPE_FLAGS_DROP) {\n+\t\t\tbfilter->flags =\n+\t\t\t\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_FLAGS_DROP;\n+\t\t}\n+\n+\t\tret = bnxt_hwrm_set_ntuple_filter(bp, bfilter->dst_id, bfilter);\n+\t\tif (ret)\n+\t\t\tgoto cleanup;\n+\t\tSTAILQ_INSERT_TAIL(&vnic->filter, bfilter, next);\n+\t\tbreak;\n+\tcase RTE_ETH_FILTER_DELETE:\n+\t\tfilter1 = bnxt_match_and_validate_ether_filter(bp, efilter,\n+\t\t\t\t\t\t\tvnic0, vnic, &ret);\n+\t\tif (ret == -EEXIST) {\n+\t\t\tret = bnxt_hwrm_clear_ntuple_filter(bp, filter1);\n+\n+\t\t\tSTAILQ_REMOVE(&vnic->filter, filter1, bnxt_filter_info,\n+\t\t\t\t      next);\n+\t\t\tbnxt_free_filter(bp, filter1);\n+\t\t} else if (ret == 0) {\n+\t\t\tRTE_LOG(ERR, PMD, \"No matching filter found\\n\");\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tRTE_LOG(ERR, PMD, \"unsupported operation %u.\", filter_op);\n+\t\tret = -EINVAL;\n+\t\tgoto error;\n+\t}\n+\treturn ret;\n+cleanup:\n+\tbnxt_free_filter(bp, bfilter);\n+error:\n+\treturn ret;\n+}\n+\n+static int\n+bnxt_filter_ctrl_op(struct rte_eth_dev *dev __rte_unused,\n+\t\t    enum rte_filter_type filter_type,\n+\t\t    enum rte_filter_op filter_op, void *arg)\n+{\n+\tint ret = 0;\n+\n+\tswitch (filter_type) {\n+\tcase RTE_ETH_FILTER_NTUPLE:\n+\tcase RTE_ETH_FILTER_FDIR:\n+\tcase RTE_ETH_FILTER_TUNNEL:\n+\t\t/* FALLTHROUGH */\n+\t\tRTE_LOG(ERR, PMD,\n+\t\t\t\"filter type: %d: To be implemented\\n\", filter_type);\n+\t\tbreak;\n+\tcase RTE_ETH_FILTER_ETHERTYPE:\n+\t\tret = bnxt_ethertype_filter(dev, filter_op, arg);\n+\t\tbreak;\n+\tcase RTE_ETH_FILTER_GENERIC:\n+\t\tif (filter_op != RTE_ETH_FILTER_GET)\n+\t\t\treturn -EINVAL;\n+\t\t*(const void **)arg = &bnxt_flow_ops;\n+\t\tbreak;\n+\tdefault:\n+\t\tRTE_LOG(ERR, PMD,\n+\t\t\t\"Filter type (%d) not supported\", filter_type);\n+\t\tret = -EINVAL;\n+\t\tbreak;\n+\t}\n+\treturn ret;\n+}\n+\n /*\n  * Initialization\n  */\n@@ -1699,6 +1882,7 @@ static const struct eth_dev_ops bnxt_dev_ops = {\n \t.rx_queue_count = bnxt_rx_queue_count_op,\n \t.rx_descriptor_status = bnxt_rx_descriptor_status_op,\n \t.tx_descriptor_status = bnxt_tx_descriptor_status_op,\n+\t.filter_ctrl = bnxt_filter_ctrl_op,\n };\n \n static bool bnxt_vf_pciid(uint16_t id)\ndiff --git a/drivers/net/bnxt/bnxt_filter.c b/drivers/net/bnxt/bnxt_filter.c\nindex e9aac2714..8ddf81ac7 100644\n--- a/drivers/net/bnxt/bnxt_filter.c\n+++ b/drivers/net/bnxt/bnxt_filter.c\n@@ -35,6 +35,9 @@\n \n #include <rte_log.h>\n #include <rte_malloc.h>\n+#include <rte_flow.h>\n+#include <rte_flow_driver.h>\n+#include <rte_tailq.h>\n \n #include \"bnxt.h\"\n #include \"bnxt_filter.h\"\n@@ -94,6 +97,8 @@ void bnxt_init_filters(struct bnxt *bp)\n \tfor (i = 0; i < max_filters; i++) {\n \t\tfilter = &bp->filter_info[i];\n \t\tfilter->fw_l2_filter_id = -1;\n+\t\tfilter->fw_em_filter_id = -1;\n+\t\tfilter->fw_ntuple_filter_id = -1;\n \t\tSTAILQ_INSERT_TAIL(&bp->free_filter_list, filter, next);\n \t}\n }\n@@ -121,7 +126,7 @@ void bnxt_free_all_filters(struct bnxt *bp)\n \n \tfor (i = 0; i < bp->pf.max_vfs; i++) {\n \t\tSTAILQ_FOREACH(filter, &bp->pf.vf_info[i].filter, next) {\n-\t\t\tbnxt_hwrm_clear_filter(bp, filter);\n+\t\t\tbnxt_hwrm_clear_l2_filter(bp, filter);\n \t\t}\n \t}\n }\n@@ -142,7 +147,7 @@ void bnxt_free_filter_mem(struct bnxt *bp)\n \t\tif (filter->fw_l2_filter_id != ((uint64_t)-1)) {\n \t\t\tRTE_LOG(ERR, PMD, \"HWRM filter is not freed??\\n\");\n \t\t\t/* Call HWRM to try to free filter again */\n-\t\t\trc = bnxt_hwrm_clear_filter(bp, filter);\n+\t\t\trc = bnxt_hwrm_clear_l2_filter(bp, filter);\n \t\t\tif (rc)\n \t\t\t\tRTE_LOG(ERR, PMD,\n \t\t\t\t       \"HWRM filter cannot be freed rc = %d\\n\",\n@@ -174,3 +179,864 @@ int bnxt_alloc_filter_mem(struct bnxt *bp)\n \tbp->filter_info = filter_mem;\n \treturn 0;\n }\n+\n+struct bnxt_filter_info *bnxt_get_unused_filter(struct bnxt *bp)\n+{\n+\tstruct bnxt_filter_info *filter;\n+\n+\t/* Find the 1st unused filter from the free_filter_list pool*/\n+\tfilter = STAILQ_FIRST(&bp->free_filter_list);\n+\tif (!filter) {\n+\t\tRTE_LOG(ERR, PMD, \"No more free filter resources\\n\");\n+\t\treturn NULL;\n+\t}\n+\tSTAILQ_REMOVE_HEAD(&bp->free_filter_list, next);\n+\n+\treturn filter;\n+}\n+\n+void bnxt_free_filter(struct bnxt *bp, struct bnxt_filter_info *filter)\n+{\n+\tSTAILQ_INSERT_TAIL(&bp->free_filter_list, filter, next);\n+}\n+\n+static int\n+bnxt_flow_agrs_validate(const struct rte_flow_attr *attr,\n+\t\t\tconst struct rte_flow_item pattern[],\n+\t\t\tconst struct rte_flow_action actions[],\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tif (!pattern) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\tRTE_FLOW_ERROR_TYPE_ITEM_NUM,\n+\t\t\tNULL, \"NULL pattern.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (!actions) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ACTION_NUM,\n+\t\t\t\t   NULL, \"NULL action.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (!attr) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR,\n+\t\t\t\t   NULL, \"NULL attribute.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static const struct rte_flow_item *\n+nxt_non_void_pattern(const struct rte_flow_item *cur)\n+{\n+\twhile (1) {\n+\t\tif (cur->type != RTE_FLOW_ITEM_TYPE_VOID)\n+\t\t\treturn cur;\n+\t\tcur++;\n+\t}\n+}\n+\n+static const struct rte_flow_action *\n+nxt_non_void_action(const struct rte_flow_action *cur)\n+{\n+\twhile (1) {\n+\t\tif (cur->type != RTE_FLOW_ACTION_TYPE_VOID)\n+\t\t\treturn cur;\n+\t\tcur++;\n+\t}\n+}\n+\n+static inline int check_zero_bytes(const uint8_t *bytes, int len)\n+{\n+\tint i;\n+\tfor (i = 0; i < len; i++)\n+\t\tif (bytes[i] != 0x00)\n+\t\t\treturn 0;\n+\treturn 1;\n+}\n+\n+static int\n+bnxt_filter_type_check(const struct rte_flow_item pattern[],\n+\t\t       struct rte_flow_error *error __rte_unused)\n+{\n+\tconst struct rte_flow_item *item = nxt_non_void_pattern(pattern);\n+\tint use_ntuple = 1;\n+\n+\twhile (item->type != RTE_FLOW_ITEM_TYPE_END) {\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\tuse_ntuple = 1;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n+\t\t\tuse_ntuple = 0;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\t/* FALLTHROUGH */\n+\t\t\t/* need ntuple match, reset exact match */\n+\t\t\tif (!use_ntuple) {\n+\t\t\t\tRTE_LOG(ERR, PMD,\n+\t\t\t\t\t\"VLAN flow cannot use NTUPLE filter\\n\");\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"Cannot use VLAN with NTUPLE\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\t\t\tuse_ntuple |= 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tRTE_LOG(ERR, PMD, \"Unknown Flow type\");\n+\t\t\tuse_ntuple |= 1;\n+\t\t}\n+\t\titem++;\n+\t}\n+\treturn use_ntuple;\n+}\n+\n+static int\n+bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],\n+\t\t\t\t  struct rte_flow_error *error,\n+\t\t\t\t  struct bnxt_filter_info *filter)\n+{\n+\tconst struct rte_flow_item *item = nxt_non_void_pattern(pattern);\n+\tconst struct rte_flow_item_vlan *vlan_spec, *vlan_mask;\n+\tconst struct rte_flow_item_ipv4 *ipv4_spec, *ipv4_mask;\n+\tconst struct rte_flow_item_ipv6 *ipv6_spec, *ipv6_mask;\n+\tconst struct rte_flow_item_tcp *tcp_spec, *tcp_mask;\n+\tconst struct rte_flow_item_udp *udp_spec, *udp_mask;\n+\tconst struct rte_flow_item_eth *eth_spec, *eth_mask;\n+\tconst struct rte_flow_item_nvgre *nvgre_spec;\n+\tconst struct rte_flow_item_nvgre *nvgre_mask;\n+\tconst struct rte_flow_item_vxlan *vxlan_spec;\n+\tconst struct rte_flow_item_vxlan *vxlan_mask;\n+\tuint8_t vni_mask[] = {0xFF, 0xFF, 0xFF};\n+\tuint8_t tni_mask[] = {0xFF, 0xFF, 0xFF};\n+\tuint32_t tenant_id_be = 0;\n+\tbool vni_masked = 0;\n+\tbool tni_masked = 0;\n+\tint use_ntuple;\n+\tuint32_t en = 0;\n+\n+\tuse_ntuple = bnxt_filter_type_check(pattern, error);\n+\tRTE_LOG(ERR, PMD, \"Use NTUPLE %d\\n\", use_ntuple);\n+\tif (use_ntuple < 0)\n+\t\treturn use_ntuple;\n+\n+\tfilter->filter_type = use_ntuple ?\n+\t\tHWRM_CFA_NTUPLE_FILTER : HWRM_CFA_EM_FILTER;\n+\n+\twhile (item->type != RTE_FLOW_ITEM_TYPE_END) {\n+\t\tif (item->last) {\n+\t\t\t/* last or range is NOT supported as match criteria */\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"No support for range\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t\tif (!item->spec || !item->mask) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"spec/mask is NULL\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t\tswitch (item->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\teth_spec = (const struct rte_flow_item_eth *)item->spec;\n+\t\t\teth_mask = (const struct rte_flow_item_eth *)item->mask;\n+\n+\t\t\t/* Source MAC address mask cannot be partially set.\n+\t\t\t * Should be All 0's or all 1's.\n+\t\t\t * Destination MAC address mask must not be partially\n+\t\t\t * set. Should be all 1's or all 0's.\n+\t\t\t */\n+\t\t\tif ((!is_zero_ether_addr(&eth_mask->src) &&\n+\t\t\t     !is_broadcast_ether_addr(&eth_mask->src)) ||\n+\t\t\t    (!is_zero_ether_addr(&eth_mask->dst) &&\n+\t\t\t     !is_broadcast_ether_addr(&eth_mask->dst))) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"MAC_addr mask not valid\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\t/* Mask is not allowed. Only exact matches are */\n+\t\t\tif ((eth_mask->type & UINT16_MAX) != UINT16_MAX) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"ethertype mask not valid\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tif (is_broadcast_ether_addr(&eth_mask->dst)) {\n+\t\t\t\trte_memcpy(filter->dst_macaddr,\n+\t\t\t\t\t   &eth_spec->dst, 6);\n+\t\t\t\ten |= use_ntuple ?\n+\t\t\t\t\tNTUPLE_FLTR_ALLOC_INPUT_EN_DST_MACADDR :\n+\t\t\t\t\tEM_FLOW_ALLOC_INPUT_EN_DST_MACADDR;\n+\t\t\t}\n+\t\t\tif (is_broadcast_ether_addr(&eth_mask->src)) {\n+\t\t\t\trte_memcpy(filter->src_macaddr,\n+\t\t\t\t\t   &eth_spec->src, 6);\n+\t\t\t\ten |= use_ntuple ?\n+\t\t\t\t\tNTUPLE_FLTR_ALLOC_INPUT_EN_SRC_MACADDR :\n+\t\t\t\t\tEM_FLOW_ALLOC_INPUT_EN_SRC_MACADDR;\n+\t\t\t} /*\n+\t\t\t   * else {\n+\t\t\t   *  RTE_LOG(ERR, PMD, \"Handle this condition\\n\");\n+\t\t\t   * }\n+\t\t\t   */\n+\t\t\tif (eth_spec->type) {\n+\t\t\t\tfilter->ethertype =\n+\t\t\t\t\trte_be_to_cpu_16(eth_spec->type);\n+\t\t\t\ten |= use_ntuple ?\n+\t\t\t\t\tNTUPLE_FLTR_ALLOC_INPUT_EN_ETHERTYPE :\n+\t\t\t\t\tEM_FLOW_ALLOC_INPUT_EN_ETHERTYPE;\n+\t\t\t}\n+\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n+\t\t\tvlan_spec =\n+\t\t\t\t(const struct rte_flow_item_vlan *)item->spec;\n+\t\t\tvlan_mask =\n+\t\t\t\t(const struct rte_flow_item_vlan *)item->mask;\n+\t\t\tif (vlan_mask->tci & 0xFFFF && !vlan_mask->tpid) {\n+\t\t\t\t/* Only the VLAN ID can be matched. */\n+\t\t\t\tfilter->l2_ovlan =\n+\t\t\t\t\trte_be_to_cpu_16(vlan_spec->tci &\n+\t\t\t\t\t\t\t 0xFFF);\n+\t\t\t\ten |= EM_FLOW_ALLOC_INPUT_EN_OVLAN_VID;\n+\t\t\t} else {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"VLAN mask is invalid\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\t/* If mask is not involved, we could use EM filters. */\n+\t\t\tipv4_spec =\n+\t\t\t\t(const struct rte_flow_item_ipv4 *)item->spec;\n+\t\t\tipv4_mask =\n+\t\t\t\t(const struct rte_flow_item_ipv4 *)item->mask;\n+\t\t\t/* Only IP DST and SRC fields are maskable. */\n+\t\t\tif (ipv4_mask->hdr.version_ihl ||\n+\t\t\t    ipv4_mask->hdr.type_of_service ||\n+\t\t\t    ipv4_mask->hdr.total_length ||\n+\t\t\t    ipv4_mask->hdr.packet_id ||\n+\t\t\t    ipv4_mask->hdr.fragment_offset ||\n+\t\t\t    ipv4_mask->hdr.time_to_live ||\n+\t\t\t    ipv4_mask->hdr.next_proto_id ||\n+\t\t\t    ipv4_mask->hdr.hdr_checksum) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Invalid IPv4 mask.\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\t\t\tfilter->dst_ipaddr[0] = ipv4_spec->hdr.dst_addr;\n+\t\t\tfilter->src_ipaddr[0] = ipv4_spec->hdr.src_addr;\n+\t\t\tif (use_ntuple)\n+\t\t\t\ten |= NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_IPADDR |\n+\t\t\t\t\tNTUPLE_FLTR_ALLOC_INPUT_EN_DST_IPADDR;\n+\t\t\telse\n+\t\t\t\ten |= EM_FLOW_ALLOC_INPUT_EN_SRC_IPADDR |\n+\t\t\t\t\tEM_FLOW_ALLOC_INPUT_EN_DST_IPADDR;\n+\t\t\tif (ipv4_mask->hdr.src_addr) {\n+\t\t\t\tfilter->src_ipaddr_mask[0] =\n+\t\t\t\t\tipv4_mask->hdr.src_addr;\n+\t\t\t\ten |= !use_ntuple ? 0 :\n+\t\t\t\t     NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_IPADDR_MASK;\n+\t\t\t}\n+\t\t\tif (ipv4_mask->hdr.dst_addr) {\n+\t\t\t\tfilter->dst_ipaddr_mask[0] =\n+\t\t\t\t\tipv4_mask->hdr.dst_addr;\n+\t\t\t\ten |= !use_ntuple ? 0 :\n+\t\t\t\t     NTUPLE_FLTR_ALLOC_INPUT_EN_DST_IPADDR_MASK;\n+\t\t\t}\n+\t\t\tfilter->ip_addr_type = use_ntuple ?\n+\t\t\t HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_IP_ADDR_TYPE_IPV4 :\n+\t\t\t HWRM_CFA_EM_FLOW_ALLOC_INPUT_IP_ADDR_TYPE_IPV4;\n+\t\t\tif (ipv4_spec->hdr.next_proto_id) {\n+\t\t\t\tfilter->ip_protocol =\n+\t\t\t\t\tipv4_spec->hdr.next_proto_id;\n+\t\t\t\tif (use_ntuple)\n+\t\t\t\t\ten |= NTUPLE_FLTR_ALLOC_IN_EN_IP_PROTO;\n+\t\t\t\telse\n+\t\t\t\t\ten |= EM_FLOW_ALLOC_INPUT_EN_IP_PROTO;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n+\t\t\tipv6_spec =\n+\t\t\t\t(const struct rte_flow_item_ipv6 *)item->spec;\n+\t\t\tipv6_mask =\n+\t\t\t\t(const struct rte_flow_item_ipv6 *)item->mask;\n+\n+\t\t\t/* Only IP DST and SRC fields are maskable. */\n+\t\t\tif (ipv6_mask->hdr.vtc_flow ||\n+\t\t\t    ipv6_mask->hdr.payload_len ||\n+\t\t\t    ipv6_mask->hdr.proto ||\n+\t\t\t    ipv6_mask->hdr.hop_limits) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Invalid IPv6 mask.\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tif (use_ntuple)\n+\t\t\t\ten |= NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_IPADDR |\n+\t\t\t\t\tNTUPLE_FLTR_ALLOC_INPUT_EN_DST_IPADDR;\n+\t\t\telse\n+\t\t\t\ten |= EM_FLOW_ALLOC_INPUT_EN_SRC_IPADDR |\n+\t\t\t\t\tEM_FLOW_ALLOC_INPUT_EN_DST_IPADDR;\n+\t\t\trte_memcpy(filter->src_ipaddr,\n+\t\t\t\t   ipv6_spec->hdr.src_addr, 16);\n+\t\t\trte_memcpy(filter->dst_ipaddr,\n+\t\t\t\t   ipv6_spec->hdr.dst_addr, 16);\n+\t\t\tif (!check_zero_bytes(ipv6_mask->hdr.src_addr, 16)) {\n+\t\t\t\trte_memcpy(filter->src_ipaddr_mask,\n+\t\t\t\t\t   ipv6_mask->hdr.src_addr, 16);\n+\t\t\t\ten |= !use_ntuple ? 0 :\n+\t\t\t\t    NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_IPADDR_MASK;\n+\t\t\t}\n+\t\t\tif (!check_zero_bytes(ipv6_mask->hdr.dst_addr, 16)) {\n+\t\t\t\trte_memcpy(filter->dst_ipaddr_mask,\n+\t\t\t\t\t   ipv6_mask->hdr.dst_addr, 16);\n+\t\t\t\ten |= !use_ntuple ? 0 :\n+\t\t\t\t     NTUPLE_FLTR_ALLOC_INPUT_EN_DST_IPADDR_MASK;\n+\t\t\t}\n+\t\t\tfilter->ip_addr_type = use_ntuple ?\n+\t\t\t\tNTUPLE_FLTR_ALLOC_INPUT_IP_ADDR_TYPE_IPV6 :\n+\t\t\t\tEM_FLOW_ALLOC_INPUT_IP_ADDR_TYPE_IPV6;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\t\ttcp_spec = (const struct rte_flow_item_tcp *)item->spec;\n+\t\t\ttcp_mask = (const struct rte_flow_item_tcp *)item->mask;\n+\n+\t\t\t/* Check TCP mask. Only DST & SRC ports are maskable */\n+\t\t\tif (tcp_mask->hdr.sent_seq ||\n+\t\t\t    tcp_mask->hdr.recv_ack ||\n+\t\t\t    tcp_mask->hdr.data_off ||\n+\t\t\t    tcp_mask->hdr.tcp_flags ||\n+\t\t\t    tcp_mask->hdr.rx_win ||\n+\t\t\t    tcp_mask->hdr.cksum ||\n+\t\t\t    tcp_mask->hdr.tcp_urp) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Invalid TCP mask\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\t\t\tfilter->src_port = tcp_spec->hdr.src_port;\n+\t\t\tfilter->dst_port = tcp_spec->hdr.dst_port;\n+\t\t\tif (use_ntuple)\n+\t\t\t\ten |= NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_PORT |\n+\t\t\t\t\tNTUPLE_FLTR_ALLOC_INPUT_EN_DST_PORT;\n+\t\t\telse\n+\t\t\t\ten |= EM_FLOW_ALLOC_INPUT_EN_SRC_PORT |\n+\t\t\t\t\tEM_FLOW_ALLOC_INPUT_EN_DST_PORT;\n+\t\t\tif (tcp_mask->hdr.dst_port) {\n+\t\t\t\tfilter->dst_port_mask = tcp_mask->hdr.dst_port;\n+\t\t\t\ten |= !use_ntuple ? 0 :\n+\t\t\t\t  NTUPLE_FLTR_ALLOC_INPUT_EN_DST_PORT_MASK;\n+\t\t\t}\n+\t\t\tif (tcp_mask->hdr.src_port) {\n+\t\t\t\tfilter->src_port_mask = tcp_mask->hdr.src_port;\n+\t\t\t\ten |= !use_ntuple ? 0 :\n+\t\t\t\t  NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_PORT_MASK;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tudp_spec = (const struct rte_flow_item_udp *)item->spec;\n+\t\t\tudp_mask = (const struct rte_flow_item_udp *)item->mask;\n+\n+\t\t\tif (udp_mask->hdr.dgram_len ||\n+\t\t\t    udp_mask->hdr.dgram_cksum) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Invalid UDP mask\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tfilter->src_port = udp_spec->hdr.src_port;\n+\t\t\tfilter->dst_port = udp_spec->hdr.dst_port;\n+\t\t\tif (use_ntuple)\n+\t\t\t\ten |= NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_PORT |\n+\t\t\t\t\tNTUPLE_FLTR_ALLOC_INPUT_EN_DST_PORT;\n+\t\t\telse\n+\t\t\t\ten |= EM_FLOW_ALLOC_INPUT_EN_SRC_PORT |\n+\t\t\t\t\tEM_FLOW_ALLOC_INPUT_EN_DST_PORT;\n+\n+\t\t\tif (udp_mask->hdr.dst_port) {\n+\t\t\t\tfilter->dst_port_mask = udp_mask->hdr.dst_port;\n+\t\t\t\ten |= !use_ntuple ? 0 :\n+\t\t\t\t  NTUPLE_FLTR_ALLOC_INPUT_EN_DST_PORT_MASK;\n+\t\t\t}\n+\t\t\tif (udp_mask->hdr.src_port) {\n+\t\t\t\tfilter->src_port_mask = udp_mask->hdr.src_port;\n+\t\t\t\ten |= !use_ntuple ? 0 :\n+\t\t\t\t  NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_PORT_MASK;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\t\tvxlan_spec =\n+\t\t\t\t(const struct rte_flow_item_vxlan *)item->spec;\n+\t\t\tvxlan_mask =\n+\t\t\t\t(const struct rte_flow_item_vxlan *)item->mask;\n+\t\t\t/* Check if VXLAN item is used to describe protocol.\n+\t\t\t * If yes, both spec and mask should be NULL.\n+\t\t\t * If no, both spec and mask shouldn't be NULL.\n+\t\t\t */\n+\t\t\tif ((!vxlan_spec && vxlan_mask) ||\n+\t\t\t    (vxlan_spec && !vxlan_mask)) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Invalid VXLAN item\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tif (vxlan_spec->rsvd1 || vxlan_spec->rsvd0[0] ||\n+\t\t\t    vxlan_spec->rsvd0[1] || vxlan_spec->rsvd0[2] ||\n+\t\t\t    (vxlan_spec->flags != 0x8)) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Invalid VXLAN item\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\t/* Check if VNI is masked. */\n+\t\t\tif (vxlan_spec && vxlan_mask) {\n+\t\t\t\tvni_masked =\n+\t\t\t\t\t!!memcmp(vxlan_mask->vni, vni_mask,\n+\t\t\t\t\t\t RTE_DIM(vni_mask));\n+\t\t\t\tif (vni_masked) {\n+\t\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"Invalid VNI mask\");\n+\t\t\t\t\treturn -rte_errno;\n+\t\t\t\t}\n+\n+\t\t\t\trte_memcpy(((uint8_t *)&tenant_id_be + 1),\n+\t\t\t\t\t   vxlan_spec->vni, 3);\n+\t\t\t\tfilter->vni =\n+\t\t\t\t\trte_be_to_cpu_32(tenant_id_be);\n+\t\t\t\tfilter->tunnel_type =\n+\t\t\t\t CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_NVGRE:\n+\t\t\tnvgre_spec =\n+\t\t\t\t(const struct rte_flow_item_nvgre *)item->spec;\n+\t\t\tnvgre_mask =\n+\t\t\t\t(const struct rte_flow_item_nvgre *)item->mask;\n+\t\t\t/* Check if NVGRE item is used to describe protocol.\n+\t\t\t * If yes, both spec and mask should be NULL.\n+\t\t\t * If no, both spec and mask shouldn't be NULL.\n+\t\t\t */\n+\t\t\tif ((!nvgre_spec && nvgre_mask) ||\n+\t\t\t    (nvgre_spec && !nvgre_mask)) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Invalid NVGRE item\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tif ((nvgre_spec->c_k_s_rsvd0_ver != 0x2000) ||\n+\t\t\t    (nvgre_spec->protocol != 0x6558)) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Invalid NVGRE item\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tif (nvgre_spec && nvgre_mask) {\n+\t\t\t\ttni_masked =\n+\t\t\t\t\t!!memcmp(nvgre_mask->tni, tni_mask,\n+\t\t\t\t\t\t RTE_DIM(tni_mask));\n+\t\t\t\tif (tni_masked) {\n+\t\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t       RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t       item,\n+\t\t\t\t\t\t       \"Invalid TNI mask\");\n+\t\t\t\t\treturn -rte_errno;\n+\t\t\t\t}\n+\t\t\t\trte_memcpy(((uint8_t *)&tenant_id_be + 1),\n+\t\t\t\t\t   nvgre_spec->tni, 3);\n+\t\t\t\tfilter->vni =\n+\t\t\t\t\trte_be_to_cpu_32(tenant_id_be);\n+\t\t\t\tfilter->tunnel_type =\n+\t\t\t\t CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_NVGRE;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\titem++;\n+\t}\n+\tfilter->enables = en;\n+\n+\treturn 0;\n+}\n+\n+/* Parse attributes */\n+static int\n+bnxt_flow_parse_attr(const struct rte_flow_attr *attr,\n+\t\t     struct rte_flow_error *error)\n+{\n+\t/* Must be input direction */\n+\tif (!attr->ingress) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,\n+\t\t\t\t   attr, \"Only support ingress.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\t/* Not supported */\n+\tif (attr->egress) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,\n+\t\t\t\t   attr, \"No support for egress.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\t/* Not supported */\n+\tif (attr->priority) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,\n+\t\t\t\t   attr, \"No support for priority.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\t/* Not supported */\n+\tif (attr->group) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR_GROUP,\n+\t\t\t\t   attr, \"No support for group.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+struct bnxt_filter_info *\n+bnxt_get_l2_filter(struct bnxt *bp, struct bnxt_filter_info *nf,\n+\t\t   struct bnxt_vnic_info *vnic)\n+{\n+\tstruct bnxt_filter_info *filter1, *f0;\n+\tstruct bnxt_vnic_info *vnic0;\n+\tint rc;\n+\n+\tvnic0 = STAILQ_FIRST(&bp->ff_pool[0]);\n+\tf0 = STAILQ_FIRST(&vnic0->filter);\n+\n+\t//This flow has same DST MAC as the port/l2 filter.\n+\tif (memcmp(f0->l2_addr, nf->dst_macaddr, ETHER_ADDR_LEN) == 0)\n+\t\treturn f0;\n+\n+\t//This flow needs DST MAC which is not same as port/l2\n+\tRTE_LOG(DEBUG, PMD, \"Create L2 filter for DST MAC\\n\");\n+\tfilter1 = bnxt_get_unused_filter(bp);\n+\tfilter1->flags = HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX;\n+\tfilter1->enables = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR |\n+\t\t\tL2_FILTER_ALLOC_INPUT_EN_L2_ADDR_MASK;\n+\tmemcpy(filter1->l2_addr, nf->dst_macaddr, ETHER_ADDR_LEN);\n+\tmemset(filter1->l2_addr_mask, 0xff, ETHER_ADDR_LEN);\n+\trc = bnxt_hwrm_set_l2_filter(bp, vnic->fw_vnic_id,\n+\t\t\t\t     filter1);\n+\tif (rc) {\n+\t\tbnxt_free_filter(bp, filter1);\n+\t\treturn NULL;\n+\t}\n+\tSTAILQ_INSERT_TAIL(&vnic->filter, filter1, next);\n+\treturn filter1;\n+}\n+\n+static int\n+bnxt_validate_and_parse_flow(struct rte_eth_dev *dev,\n+\t\t\t     const struct rte_flow_item pattern[],\n+\t\t\t     const struct rte_flow_action actions[],\n+\t\t\t     const struct rte_flow_attr *attr,\n+\t\t\t     struct rte_flow_error *error,\n+\t\t\t     struct bnxt_filter_info *filter)\n+{\n+\tconst struct rte_flow_action *act = nxt_non_void_action(actions);\n+\tstruct bnxt *bp = (struct bnxt *)dev->data->dev_private;\n+\tconst struct rte_flow_action_queue *act_q;\n+\tstruct bnxt_vnic_info *vnic, *vnic0;\n+\tstruct bnxt_filter_info *filter1;\n+\tint rc;\n+\n+\tif (bp->eth_dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS) {\n+\t\tRTE_LOG(ERR, PMD, \"Cannot create flow on RSS queues\\n\");\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"Cannot create flow on RSS queues\");\n+\t\trc = -rte_errno;\n+\t\tgoto ret;\n+\t}\n+\n+\trc = bnxt_validate_and_parse_flow_type(pattern, error, filter);\n+\tif (rc != 0)\n+\t\tgoto ret;\n+\n+\trc = bnxt_flow_parse_attr(attr, error);\n+\tif (rc != 0)\n+\t\tgoto ret;\n+\t//Since we support ingress attribute only - right now.\n+\tfilter->flags = HWRM_CFA_EM_FLOW_ALLOC_INPUT_FLAGS_PATH_RX;\n+\n+\tswitch (act->type) {\n+\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n+\t\t/* Allow this flow. Redirect to a VNIC. */\n+\t\tact_q = (const struct rte_flow_action_queue *)act->conf;\n+\t\tif (act_q->index >= bp->rx_nr_rings) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ACTION, act,\n+\t\t\t\t\t   \"Invalid queue ID.\");\n+\t\t\trc = -rte_errno;\n+\t\t\tgoto ret;\n+\t\t}\n+\t\tRTE_LOG(ERR, PMD, \"Queue index %d\\n\", act_q->index);\n+\n+\t\tvnic0 = STAILQ_FIRST(&bp->ff_pool[0]);\n+\t\tvnic = STAILQ_FIRST(&bp->ff_pool[act_q->index]);\n+\t\tif (vnic == NULL) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ACTION, act,\n+\t\t\t\t\t   \"No matching VNIC for queue ID.\");\n+\t\t\trc = -rte_errno;\n+\t\t\tgoto ret;\n+\t\t}\n+\t\tfilter->dst_id = vnic->fw_vnic_id;\n+\t\tfilter1 = bnxt_get_l2_filter(bp, filter, vnic);\n+\t\tfilter->fw_l2_filter_id = filter1->fw_l2_filter_id;\n+\t\tRTE_LOG(DEBUG, PMD, \"VNIC found\\n\");\n+\t\tbreak;\n+\tcase RTE_FLOW_ACTION_TYPE_DROP:\n+\t\tvnic0 = STAILQ_FIRST(&bp->ff_pool[0]);\n+\t\tfilter1 = bnxt_get_l2_filter(bp, filter, vnic0);\n+\t\tfilter->fw_l2_filter_id = filter1->fw_l2_filter_id;\n+\t\tif (filter->filter_type == HWRM_CFA_EM_FILTER)\n+\t\t\tfilter->flags =\n+\t\t\t\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_FLAGS_DROP;\n+\t\telse\n+\t\t\tfilter->flags =\n+\t\t\t\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_FLAGS_DROP;\n+\t\tbreak;\n+\tcase RTE_FLOW_ACTION_TYPE_COUNT:\n+\t\tvnic0 = STAILQ_FIRST(&bp->ff_pool[0]);\n+\t\tfilter1 = bnxt_get_l2_filter(bp, filter, vnic0);\n+\t\tfilter->fw_l2_filter_id = filter1->fw_l2_filter_id;\n+\t\tfilter->flags = HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_FLAGS_METER;\n+\t\tbreak;\n+\tdefault:\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ACTION, act,\n+\t\t\t\t   \"Invalid action.\");\n+\t\trc = -rte_errno;\n+\t\tgoto ret;\n+\t}\n+\n+\tact = nxt_non_void_action(++act);\n+\tif (act->type != RTE_FLOW_ACTION_TYPE_END) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t   act, \"Invalid action.\");\n+\t\trc = -rte_errno;\n+\t\tgoto ret;\n+\t}\n+ret:\n+\treturn rc;\n+}\n+\n+static int\n+bnxt_flow_validate(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_attr *attr,\n+\t\tconst struct rte_flow_item pattern[],\n+\t\tconst struct rte_flow_action actions[],\n+\t\tstruct rte_flow_error *error)\n+{\n+\tstruct bnxt *bp = (struct bnxt *)dev->data->dev_private;\n+\tstruct bnxt_filter_info *filter;\n+\tint ret = 0;\n+\n+\tret = bnxt_flow_agrs_validate(attr, pattern, actions, error);\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\tfilter = bnxt_get_unused_filter(bp);\n+\tif (filter == NULL) {\n+\t\tRTE_LOG(ERR, PMD, \"Not enough resources for a new flow.\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tret = bnxt_validate_and_parse_flow(dev, pattern, actions, attr,\n+\t\t\t\t\t   error, filter);\n+\t/* No need to hold on to this filter if we are just validating flow */\n+\tbnxt_free_filter(bp, filter);\n+\n+\treturn ret;\n+}\n+\n+static struct rte_flow *\n+bnxt_flow_create(struct rte_eth_dev *dev,\n+\t\t  const struct rte_flow_attr *attr,\n+\t\t  const struct rte_flow_item pattern[],\n+\t\t  const struct rte_flow_action actions[],\n+\t\t  struct rte_flow_error *error)\n+{\n+\tstruct bnxt *bp = (struct bnxt *)dev->data->dev_private;\n+\tstruct bnxt_filter_info *filter;\n+\tstruct bnxt_vnic_info *vnic;\n+\tstruct rte_flow *flow;\n+\tunsigned int i;\n+\tint ret = 0;\n+\n+\tflow = rte_zmalloc(\"bnxt_flow\", sizeof(struct rte_flow), 0);\n+\tif (!flow) {\n+\t\trte_flow_error_set(error, ENOMEM,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t   \"Failed to allocate memory\");\n+\t\treturn flow;\n+\t}\n+\n+\tret = bnxt_flow_agrs_validate(attr, pattern, actions, error);\n+\tif (ret != 0) {\n+\t\tRTE_LOG(ERR, PMD, \"Not a validate flow.\\n\");\n+\t\tgoto free_flow;\n+\t}\n+\n+\tfilter = bnxt_get_unused_filter(bp);\n+\tif (filter == NULL) {\n+\t\tRTE_LOG(ERR, PMD, \"Not enough resources for a new flow.\\n\");\n+\t\tgoto free_flow;\n+\t}\n+\n+\tret = bnxt_validate_and_parse_flow(dev, pattern, actions, attr,\n+\t\t\t\t\t   error, filter);\n+\tif (ret != 0)\n+\t\tgoto free_flow;\n+\n+\tif (filter->filter_type == HWRM_CFA_EM_FILTER) {\n+\t\tfilter->enables |=\n+\t\t\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_L2_FILTER_ID;\n+\t\tret = bnxt_hwrm_set_em_filter(bp, filter->dst_id, filter);\n+\t}\n+\tif (filter->filter_type == HWRM_CFA_NTUPLE_FILTER) {\n+\t\tfilter->enables |=\n+\t\t\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_L2_FILTER_ID;\n+\t\tret = bnxt_hwrm_set_ntuple_filter(bp, filter->dst_id, filter);\n+\t}\n+\n+\tfor (i = 0; i < bp->nr_vnics; i++) {\n+\t\tvnic = &bp->vnic_info[i];\n+\t\tif (filter->dst_id == vnic->fw_vnic_id)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (!ret) {\n+\t\tflow->filter = filter;\n+\t\tflow->vnic = vnic;\n+\t\tRTE_LOG(ERR, PMD, \"Successfully created flow.\\n\");\n+\t\tSTAILQ_INSERT_TAIL(&vnic->flow_list, flow, next);\n+\t\treturn flow;\n+\t}\n+free_flow:\n+\tRTE_LOG(ERR, PMD, \"Failed to create flow.\\n\");\n+\tbnxt_free_filter(bp, filter);\n+\trte_flow_error_set(error, -ret,\n+\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t   \"Failed to create flow.\");\n+\trte_free(flow);\n+\tflow = NULL;\n+\treturn flow;\n+}\n+\n+static int\n+bnxt_flow_destroy(struct rte_eth_dev *dev,\n+\t\t  struct rte_flow *flow,\n+\t\t  struct rte_flow_error *error)\n+{\n+\tstruct bnxt *bp = (struct bnxt *)dev->data->dev_private;\n+\tstruct bnxt_filter_info *filter = flow->filter;\n+\tstruct bnxt_vnic_info *vnic = flow->vnic;\n+\tint ret = 0;\n+\n+\tif (filter->filter_type == HWRM_CFA_EM_FILTER)\n+\t\tret = bnxt_hwrm_clear_em_filter(bp, filter);\n+\tif (filter->filter_type == HWRM_CFA_NTUPLE_FILTER)\n+\t\tret = bnxt_hwrm_clear_ntuple_filter(bp, filter);\n+\n+\tif (!ret) {\n+\t\tSTAILQ_REMOVE(&vnic->flow_list, flow, rte_flow, next);\n+\t\trte_free(flow);\n+\t} else {\n+\t\trte_flow_error_set(error, -ret,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t   \"Failed to destroy flow.\");\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int\n+bnxt_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)\n+{\n+\tstruct bnxt *bp = (struct bnxt *)dev->data->dev_private;\n+\tstruct bnxt_vnic_info *vnic;\n+\tstruct rte_flow *flow;\n+\tunsigned int i;\n+\tint ret = 0;\n+\n+\tfor (i = 0; i < bp->nr_vnics; i++) {\n+\t\tvnic = &bp->vnic_info[i];\n+\t\tSTAILQ_FOREACH(flow, &vnic->flow_list, next) {\n+\t\t\tstruct bnxt_filter_info *filter = flow->filter;\n+\n+\t\t\tif (filter->filter_type == HWRM_CFA_EM_FILTER)\n+\t\t\t\tret = bnxt_hwrm_clear_em_filter(bp, filter);\n+\t\t\tif (filter->filter_type == HWRM_CFA_NTUPLE_FILTER)\n+\t\t\t\tret = bnxt_hwrm_clear_ntuple_filter(bp, filter);\n+\n+\t\t\tif (ret) {\n+\t\t\t\trte_flow_error_set(error, -ret,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE,\n+\t\t\t\t\t\t   NULL,\n+\t\t\t\t\t\t   \"Failed to flush flow in HW.\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tSTAILQ_REMOVE(&vnic->flow_list, flow,\n+\t\t\t\t      rte_flow, next);\n+\t\t\trte_free(flow);\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n+const struct rte_flow_ops bnxt_flow_ops = {\n+\t.validate = bnxt_flow_validate,\n+\t.create = bnxt_flow_create,\n+\t.destroy = bnxt_flow_destroy,\n+\t.flush = bnxt_flow_flush,\n+};\ndiff --git a/drivers/net/bnxt/bnxt_filter.h b/drivers/net/bnxt/bnxt_filter.h\nindex 613b2eeac..d6c1ce6df 100644\n--- a/drivers/net/bnxt/bnxt_filter.h\n+++ b/drivers/net/bnxt/bnxt_filter.h\n@@ -40,8 +40,15 @@ struct bnxt;\n struct bnxt_filter_info {\n \tSTAILQ_ENTRY(bnxt_filter_info)\tnext;\n \tuint64_t\t\tfw_l2_filter_id;\n+\tuint64_t\t\tfw_em_filter_id;\n+\tuint64_t\t\tfw_ntuple_filter_id;\n #define INVALID_MAC_INDEX\t((uint16_t)-1)\n \tuint16_t\t\tmac_index;\n+#define HWRM_CFA_L2_FILTER\t0\n+#define HWRM_CFA_EM_FILTER\t1\n+#define HWRM_CFA_NTUPLE_FILTER\t2\n+\tuint8_t                 filter_type;    //L2 or EM or NTUPLE filter\n+\tuint32_t                dst_id;\n \n \t/* Filter Characteristics */\n \tuint32_t\t\tflags;\n@@ -65,6 +72,19 @@ struct bnxt_filter_info {\n \tuint64_t\t\tl2_filter_id_hint;\n \tuint32_t\t\tsrc_id;\n \tuint8_t\t\t\tsrc_type;\n+\tuint8_t                 src_macaddr[6];\n+\tuint8_t                 dst_macaddr[6];\n+\tuint32_t                dst_ipaddr[4];\n+\tuint32_t                dst_ipaddr_mask[4];\n+\tuint32_t                src_ipaddr[4];\n+\tuint32_t                src_ipaddr_mask[4];\n+\tuint16_t                dst_port;\n+\tuint16_t                dst_port_mask;\n+\tuint16_t                src_port;\n+\tuint16_t                src_port_mask;\n+\tuint16_t                ip_protocol;\n+\tuint16_t                ip_addr_type;\n+\tuint16_t                ethertype;\n };\n \n struct bnxt_filter_info *bnxt_alloc_filter(struct bnxt *bp);\n@@ -73,5 +93,61 @@ void bnxt_init_filters(struct bnxt *bp);\n void bnxt_free_all_filters(struct bnxt *bp);\n void bnxt_free_filter_mem(struct bnxt *bp);\n int bnxt_alloc_filter_mem(struct bnxt *bp);\n+struct bnxt_filter_info *bnxt_get_unused_filter(struct bnxt *bp);\n+void bnxt_free_filter(struct bnxt *bp, struct bnxt_filter_info *filter);\n+struct bnxt_filter_info *bnxt_get_l2_filter(struct bnxt *bp,\n+\t\tstruct bnxt_filter_info *nf, struct bnxt_vnic_info *vnic);\n \n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_MACADDR\t\\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_MACADDR\n+#define EM_FLOW_ALLOC_INPUT_EN_SRC_MACADDR\t\\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_SRC_MACADDR\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_DST_MACADDR\t\\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_MACADDR\n+#define EM_FLOW_ALLOC_INPUT_EN_DST_MACADDR\t\\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_DST_MACADDR\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_ETHERTYPE   \\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_ETHERTYPE\n+#define EM_FLOW_ALLOC_INPUT_EN_ETHERTYPE       \\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_ETHERTYPE\n+#define EM_FLOW_ALLOC_INPUT_EN_OVLAN_VID       \\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_OVLAN_VID\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_IPADDR  \\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_IPADDR\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_IPADDR_MASK     \\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_IPADDR_MASK\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_DST_IPADDR  \\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_IPADDR\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_DST_IPADDR_MASK     \\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_IPADDR_MASK\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_PORT    \\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_PORT\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_PORT_MASK       \\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_PORT_MASK\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_DST_PORT    \\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_PORT\n+#define NTUPLE_FLTR_ALLOC_INPUT_EN_DST_PORT_MASK       \\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_PORT_MASK\n+#define NTUPLE_FLTR_ALLOC_IN_EN_IP_PROTO\t\\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_IP_PROTOCOL\n+#define EM_FLOW_ALLOC_INPUT_EN_SRC_IPADDR\t\\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_SRC_IPADDR\n+#define EM_FLOW_ALLOC_INPUT_EN_DST_IPADDR\t\\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_DST_IPADDR\n+#define EM_FLOW_ALLOC_INPUT_EN_SRC_PORT\t\\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_SRC_PORT\n+#define EM_FLOW_ALLOC_INPUT_EN_DST_PORT\t\\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_DST_PORT\n+#define EM_FLOW_ALLOC_INPUT_EN_IP_PROTO\t\\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_IP_PROTOCOL\n+#define EM_FLOW_ALLOC_INPUT_IP_ADDR_TYPE_IPV6\t\\\n+\tHWRM_CFA_EM_FLOW_ALLOC_INPUT_IP_ADDR_TYPE_IPV6\n+#define NTUPLE_FLTR_ALLOC_INPUT_IP_ADDR_TYPE_IPV6\t\\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_IP_ADDR_TYPE_IPV6\n+#define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN\t\\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_TUNNEL_TYPE_VXLAN\n+#define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_NVGRE\t\\\n+\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_TUNNEL_TYPE_NVGRE\n+#define L2_FILTER_ALLOC_INPUT_EN_L2_ADDR_MASK\t\\\n+\tHWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR_MASK\n #endif\ndiff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c\nindex ade96278b..204a0dcd6 100644\n--- a/drivers/net/bnxt/bnxt_hwrm.c\n+++ b/drivers/net/bnxt/bnxt_hwrm.c\n@@ -329,7 +329,7 @@ int bnxt_hwrm_cfa_vlan_antispoof_cfg(struct bnxt *bp, uint16_t fid,\n \treturn rc;\n }\n \n-int bnxt_hwrm_clear_filter(struct bnxt *bp,\n+int bnxt_hwrm_clear_l2_filter(struct bnxt *bp,\n \t\t\t   struct bnxt_filter_info *filter)\n {\n \tint rc = 0;\n@@ -353,7 +353,7 @@ int bnxt_hwrm_clear_filter(struct bnxt *bp,\n \treturn 0;\n }\n \n-int bnxt_hwrm_set_filter(struct bnxt *bp,\n+int bnxt_hwrm_set_l2_filter(struct bnxt *bp,\n \t\t\t uint16_t dst_id,\n \t\t\t struct bnxt_filter_info *filter)\n {\n@@ -363,7 +363,7 @@ int bnxt_hwrm_set_filter(struct bnxt *bp,\n \tuint32_t enables = 0;\n \n \tif (filter->fw_l2_filter_id != UINT64_MAX)\n-\t\tbnxt_hwrm_clear_filter(bp, filter);\n+\t\tbnxt_hwrm_clear_l2_filter(bp, filter);\n \n \tHWRM_PREP(req, CFA_L2_FILTER_ALLOC);\n \n@@ -1017,6 +1017,7 @@ int bnxt_hwrm_stat_ctx_alloc(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,\n \tcpr->hw_stats_ctx_id = rte_le_to_cpu_16(resp->stat_ctx_id);\n \n \tHWRM_UNLOCK();\n+\tbp->grp_info[idx].fw_stats_ctx = cpr->hw_stats_ctx_id;\n \n \treturn rc;\n }\n@@ -1133,7 +1134,7 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)\n \tint rc = 0;\n \tstruct hwrm_vnic_cfg_input req = {.req_type = 0 };\n \tstruct hwrm_vnic_cfg_output *resp = bp->hwrm_cmd_resp_addr;\n-\tuint32_t ctx_enable_flag = HWRM_VNIC_CFG_INPUT_ENABLES_RSS_RULE;\n+\tuint32_t ctx_enable_flag = 0;\n \tstruct bnxt_plcmodes_cfg pmodes;\n \n \tif (vnic->fw_vnic_id == INVALID_HW_RING_ID) {\n@@ -1149,14 +1150,15 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)\n \n \t/* Only RSS support for now TBD: COS & LB */\n \treq.enables =\n-\t    rte_cpu_to_le_32(HWRM_VNIC_CFG_INPUT_ENABLES_DFLT_RING_GRP |\n-\t\t\t     HWRM_VNIC_CFG_INPUT_ENABLES_MRU);\n+\t    rte_cpu_to_le_32(HWRM_VNIC_CFG_INPUT_ENABLES_DFLT_RING_GRP);\n \tif (vnic->lb_rule != 0xffff)\n-\t\tctx_enable_flag = HWRM_VNIC_CFG_INPUT_ENABLES_LB_RULE;\n+\t\tctx_enable_flag |= HWRM_VNIC_CFG_INPUT_ENABLES_LB_RULE;\n \tif (vnic->cos_rule != 0xffff)\n-\t\tctx_enable_flag = HWRM_VNIC_CFG_INPUT_ENABLES_COS_RULE;\n-\tif (vnic->rss_rule != 0xffff)\n-\t\tctx_enable_flag = HWRM_VNIC_CFG_INPUT_ENABLES_RSS_RULE;\n+\t\tctx_enable_flag |= HWRM_VNIC_CFG_INPUT_ENABLES_COS_RULE;\n+\tif (vnic->rss_rule != 0xffff) {\n+\t\tctx_enable_flag |= HWRM_VNIC_CFG_INPUT_ENABLES_MRU;\n+\t\tctx_enable_flag |= HWRM_VNIC_CFG_INPUT_ENABLES_RSS_RULE;\n+\t}\n \treq.enables |= rte_cpu_to_le_32(ctx_enable_flag);\n \treq.vnic_id = rte_cpu_to_le_16(vnic->fw_vnic_id);\n \treq.dflt_ring_grp = rte_cpu_to_le_16(vnic->dflt_ring_grp);\n@@ -1591,12 +1593,8 @@ int bnxt_free_all_hwrm_ring_grps(struct bnxt *bp)\n \n \tfor (idx = 0; idx < bp->rx_cp_nr_rings; idx++) {\n \n-\t\tif (bp->grp_info[idx].fw_grp_id == INVALID_HW_RING_ID) {\n-\t\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\"Attempt to free invalid ring group %d\\n\",\n-\t\t\t\tidx);\n+\t\tif (bp->grp_info[idx].fw_grp_id == INVALID_HW_RING_ID)\n \t\t\tcontinue;\n-\t\t}\n \n \t\trc = bnxt_hwrm_ring_grp_free(bp, idx);\n \n@@ -1749,9 +1747,39 @@ int bnxt_clear_hwrm_vnic_filters(struct bnxt *bp, struct bnxt_vnic_info *vnic)\n \tint rc = 0;\n \n \tSTAILQ_FOREACH(filter, &vnic->filter, next) {\n-\t\trc = bnxt_hwrm_clear_filter(bp, filter);\n-\t\tif (rc)\n-\t\t\tbreak;\n+\t\tif (filter->filter_type == HWRM_CFA_EM_FILTER)\n+\t\t\trc = bnxt_hwrm_clear_em_filter(bp, filter);\n+\t\telse if (filter->filter_type == HWRM_CFA_NTUPLE_FILTER)\n+\t\t\trc = bnxt_hwrm_clear_ntuple_filter(bp, filter);\n+\t\telse\n+\t\t\trc = bnxt_hwrm_clear_l2_filter(bp, filter);\n+\t\t//if (rc)\n+\t\t\t//break;\n+\t}\n+\treturn rc;\n+}\n+\n+static int\n+bnxt_clear_hwrm_vnic_flows(struct bnxt *bp, struct bnxt_vnic_info *vnic)\n+{\n+\tstruct bnxt_filter_info *filter;\n+\tstruct rte_flow *flow;\n+\tint rc = 0;\n+\n+\tSTAILQ_FOREACH(flow, &vnic->flow_list, next) {\n+\t\tfilter = flow->filter;\n+\t\tRTE_LOG(ERR, PMD, \"filter type %d\\n\", filter->filter_type);\n+\t\tif (filter->filter_type == HWRM_CFA_EM_FILTER)\n+\t\t\trc = bnxt_hwrm_clear_em_filter(bp, filter);\n+\t\telse if (filter->filter_type == HWRM_CFA_NTUPLE_FILTER)\n+\t\t\trc = bnxt_hwrm_clear_ntuple_filter(bp, filter);\n+\t\telse\n+\t\t\trc = bnxt_hwrm_clear_l2_filter(bp, filter);\n+\n+\t\tSTAILQ_REMOVE(&vnic->flow_list, flow, rte_flow, next);\n+\t\trte_free(flow);\n+\t\t//if (rc)\n+\t\t\t//break;\n \t}\n \treturn rc;\n }\n@@ -1762,7 +1790,15 @@ int bnxt_set_hwrm_vnic_filters(struct bnxt *bp, struct bnxt_vnic_info *vnic)\n \tint rc = 0;\n \n \tSTAILQ_FOREACH(filter, &vnic->filter, next) {\n-\t\trc = bnxt_hwrm_set_filter(bp, vnic->fw_vnic_id, filter);\n+\t\tif (filter->filter_type == HWRM_CFA_EM_FILTER)\n+\t\t\trc = bnxt_hwrm_set_em_filter(bp, filter->dst_id,\n+\t\t\t\t\t\t     filter);\n+\t\telse if (filter->filter_type == HWRM_CFA_NTUPLE_FILTER)\n+\t\t\trc = bnxt_hwrm_set_ntuple_filter(bp, filter->dst_id,\n+\t\t\t\t\t\t\t filter);\n+\t\telse\n+\t\t\trc = bnxt_hwrm_set_l2_filter(bp, vnic->fw_vnic_id,\n+\t\t\t\t\t\t     filter);\n \t\tif (rc)\n \t\t\tbreak;\n \t}\n@@ -1783,20 +1819,20 @@ void bnxt_free_tunnel_ports(struct bnxt *bp)\n \n void bnxt_free_all_hwrm_resources(struct bnxt *bp)\n {\n-\tstruct bnxt_vnic_info *vnic;\n-\tunsigned int i;\n+\tint i;\n \n \tif (bp->vnic_info == NULL)\n \t\treturn;\n \n-\tvnic = &bp->vnic_info[0];\n-\tif (BNXT_PF(bp))\n-\t\tbnxt_hwrm_cfa_l2_clear_rx_mask(bp, vnic);\n-\n-\t/* VNIC resources */\n-\tfor (i = 0; i < bp->nr_vnics; i++) {\n+\t/*\n+\t * Cleanup VNICs in reverse order, to make sure the L2 filter\n+\t * from vnic0 is last to be cleaned up.\n+\t */\n+\tfor (i = bp->nr_vnics - 1; i >= 0; i--) {\n \t\tstruct bnxt_vnic_info *vnic = &bp->vnic_info[i];\n \n+\t\tbnxt_clear_hwrm_vnic_flows(bp, vnic);\n+\n \t\tbnxt_clear_hwrm_vnic_filters(bp, vnic);\n \n \t\tbnxt_hwrm_vnic_ctx_free(bp, vnic);\n@@ -3126,3 +3162,215 @@ int bnxt_hwrm_func_qcfg_vf_dflt_vnic_id(struct bnxt *bp, int vf)\n \trte_free(vnic_ids);\n \treturn -1;\n }\n+\n+int bnxt_hwrm_set_em_filter(struct bnxt *bp,\n+\t\t\t uint16_t dst_id,\n+\t\t\t struct bnxt_filter_info *filter)\n+{\n+\tint rc = 0;\n+\tstruct hwrm_cfa_em_flow_alloc_input req = {.req_type = 0 };\n+\tstruct hwrm_cfa_em_flow_alloc_output *resp = bp->hwrm_cmd_resp_addr;\n+\tuint32_t enables = 0;\n+\n+\tif (filter->fw_em_filter_id != UINT64_MAX)\n+\t\tbnxt_hwrm_clear_em_filter(bp, filter);\n+\n+\tHWRM_PREP(req, CFA_EM_FLOW_ALLOC);\n+\n+\treq.flags = rte_cpu_to_le_32(filter->flags);\n+\n+\tenables = filter->enables |\n+\t      HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_DST_ID;\n+\treq.dst_id = rte_cpu_to_le_16(dst_id);\n+\n+\tif (filter->ip_addr_type) {\n+\t\treq.ip_addr_type = filter->ip_addr_type;\n+\t\tenables |= HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_IPADDR_TYPE;\n+\t}\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_L2_FILTER_ID)\n+\t\treq.l2_filter_id = rte_cpu_to_le_64(filter->fw_l2_filter_id);\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_SRC_MACADDR)\n+\t\tmemcpy(req.src_macaddr, filter->src_macaddr,\n+\t\t       ETHER_ADDR_LEN);\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_DST_MACADDR)\n+\t\tmemcpy(req.dst_macaddr, filter->dst_macaddr,\n+\t\t       ETHER_ADDR_LEN);\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_OVLAN_VID)\n+\t\treq.ovlan_vid = filter->l2_ovlan;\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_IVLAN_VID)\n+\t\treq.ivlan_vid = filter->l2_ivlan;\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_ETHERTYPE)\n+\t\treq.ethertype = rte_cpu_to_be_16(filter->ethertype);\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_IP_PROTOCOL)\n+\t\treq.ip_protocol = filter->ip_protocol;\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_SRC_IPADDR)\n+\t\treq.src_ipaddr[0] = rte_cpu_to_be_32(filter->src_ipaddr[0]);\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_DST_IPADDR)\n+\t\treq.dst_ipaddr[0] = rte_cpu_to_be_32(filter->dst_ipaddr[0]);\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_SRC_PORT)\n+\t\treq.src_port = rte_cpu_to_be_16(filter->src_port);\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_DST_PORT)\n+\t\treq.dst_port = rte_cpu_to_be_16(filter->dst_port);\n+\tif (enables &\n+\t    HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_MIRROR_VNIC_ID)\n+\t\treq.mirror_vnic_id = filter->mirror_vnic_id;\n+\n+\treq.enables = rte_cpu_to_le_32(enables);\n+\n+\trc = bnxt_hwrm_send_message(bp, &req, sizeof(req));\n+\n+\tHWRM_CHECK_RESULT();\n+\n+\tfilter->fw_em_filter_id = rte_le_to_cpu_64(resp->em_filter_id);\n+\tHWRM_UNLOCK();\n+\n+\treturn rc;\n+}\n+\n+int bnxt_hwrm_clear_em_filter(struct bnxt *bp, struct bnxt_filter_info *filter)\n+{\n+\tint rc = 0;\n+\tstruct hwrm_cfa_em_flow_free_input req = {.req_type = 0 };\n+\tstruct hwrm_cfa_em_flow_free_output *resp = bp->hwrm_cmd_resp_addr;\n+\n+\tif (filter->fw_em_filter_id == UINT64_MAX)\n+\t\treturn 0;\n+\n+\tRTE_LOG(ERR, PMD, \"Clear EM filter\\n\");\n+\tHWRM_PREP(req, CFA_EM_FLOW_FREE);\n+\n+\treq.em_filter_id = rte_cpu_to_le_64(filter->fw_em_filter_id);\n+\n+\trc = bnxt_hwrm_send_message(bp, &req, sizeof(req));\n+\n+\tHWRM_CHECK_RESULT();\n+\tHWRM_UNLOCK();\n+\n+\tfilter->fw_em_filter_id = -1;\n+\tfilter->fw_l2_filter_id = -1;\n+\n+\treturn 0;\n+}\n+\n+int bnxt_hwrm_set_ntuple_filter(struct bnxt *bp,\n+\t\t\t uint16_t dst_id,\n+\t\t\t struct bnxt_filter_info *filter)\n+{\n+\tint rc = 0;\n+\tstruct hwrm_cfa_ntuple_filter_alloc_input req = {.req_type = 0 };\n+\tstruct hwrm_cfa_ntuple_filter_alloc_output *resp =\n+\t\t\t\t\t\tbp->hwrm_cmd_resp_addr;\n+\tuint32_t enables = 0;\n+\n+\tif (filter->fw_ntuple_filter_id != UINT64_MAX)\n+\t\tbnxt_hwrm_clear_ntuple_filter(bp, filter);\n+\n+\tHWRM_PREP(req, CFA_NTUPLE_FILTER_ALLOC);\n+\n+\treq.flags = rte_cpu_to_le_32(filter->flags);\n+\n+\tenables = filter->enables |\n+\t      HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_ID;\n+\treq.dst_id = rte_cpu_to_le_16(dst_id);\n+\n+\n+\tif (filter->ip_addr_type) {\n+\t\treq.ip_addr_type = filter->ip_addr_type;\n+\t\tenables |=\n+\t\t\tHWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_IPADDR_TYPE;\n+\t}\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_L2_FILTER_ID)\n+\t\treq.l2_filter_id = rte_cpu_to_le_64(filter->fw_l2_filter_id);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_MACADDR)\n+\t\tmemcpy(req.src_macaddr, filter->src_macaddr,\n+\t\t       ETHER_ADDR_LEN);\n+\t//if (enables &\n+\t    //HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_MACADDR)\n+\t\t//memcpy(req.dst_macaddr, filter->dst_macaddr,\n+\t\t       //ETHER_ADDR_LEN);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_ETHERTYPE)\n+\t\treq.ethertype = rte_cpu_to_be_16(filter->ethertype);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_IP_PROTOCOL)\n+\t\treq.ip_protocol = filter->ip_protocol;\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_IPADDR)\n+\t\treq.src_ipaddr[0] = rte_cpu_to_le_32(filter->src_ipaddr[0]);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_IPADDR_MASK)\n+\t\treq.src_ipaddr_mask[0] =\n+\t\t\trte_cpu_to_le_32(filter->src_ipaddr_mask[0]);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_IPADDR)\n+\t\treq.dst_ipaddr[0] = rte_cpu_to_le_32(filter->dst_ipaddr[0]);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_IPADDR_MASK)\n+\t\treq.dst_ipaddr_mask[0] =\n+\t\t\trte_cpu_to_be_32(filter->dst_ipaddr_mask[0]);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_PORT)\n+\t\treq.src_port = rte_cpu_to_le_16(filter->src_port);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_SRC_PORT_MASK)\n+\t\treq.src_port_mask = rte_cpu_to_le_16(filter->src_port_mask);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_PORT)\n+\t\treq.dst_port = rte_cpu_to_le_16(filter->dst_port);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_DST_PORT_MASK)\n+\t\treq.dst_port_mask = rte_cpu_to_le_16(filter->dst_port_mask);\n+\tif (enables &\n+\t    HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_MIRROR_VNIC_ID)\n+\t\treq.mirror_vnic_id = filter->mirror_vnic_id;\n+\n+\treq.enables = rte_cpu_to_le_32(enables);\n+\n+\trc = bnxt_hwrm_send_message(bp, &req, sizeof(req));\n+\n+\tHWRM_CHECK_RESULT();\n+\n+\tfilter->fw_ntuple_filter_id = rte_le_to_cpu_64(resp->ntuple_filter_id);\n+\tHWRM_UNLOCK();\n+\n+\treturn rc;\n+}\n+\n+int bnxt_hwrm_clear_ntuple_filter(struct bnxt *bp,\n+\t\t\t\tstruct bnxt_filter_info *filter)\n+{\n+\tint rc = 0;\n+\tstruct hwrm_cfa_ntuple_filter_free_input req = {.req_type = 0 };\n+\tstruct hwrm_cfa_ntuple_filter_free_output *resp =\n+\t\t\t\t\t\tbp->hwrm_cmd_resp_addr;\n+\n+\tif (filter->fw_ntuple_filter_id == UINT64_MAX)\n+\t\treturn 0;\n+\n+\tHWRM_PREP(req, CFA_NTUPLE_FILTER_FREE);\n+\n+\treq.ntuple_filter_id = rte_cpu_to_le_64(filter->fw_ntuple_filter_id);\n+\n+\trc = bnxt_hwrm_send_message(bp, &req, sizeof(req));\n+\n+\tHWRM_CHECK_RESULT();\n+\tHWRM_UNLOCK();\n+\n+\tfilter->fw_ntuple_filter_id = -1;\n+\tfilter->fw_l2_filter_id = -1;\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/net/bnxt/bnxt_hwrm.h b/drivers/net/bnxt/bnxt_hwrm.h\nindex 51cd0dd42..bd9017f17 100644\n--- a/drivers/net/bnxt/bnxt_hwrm.h\n+++ b/drivers/net/bnxt/bnxt_hwrm.h\n@@ -51,9 +51,9 @@ int bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt *bp, struct bnxt_vnic_info *vnic,\n int bnxt_hwrm_cfa_vlan_antispoof_cfg(struct bnxt *bp, uint16_t fid,\n \t\t\tuint16_t vlan_count,\n \t\t\tstruct bnxt_vlan_antispoof_table_entry *vlan_table);\n-int bnxt_hwrm_clear_filter(struct bnxt *bp,\n+int bnxt_hwrm_clear_l2_filter(struct bnxt *bp,\n \t\t\t   struct bnxt_filter_info *filter);\n-int bnxt_hwrm_set_filter(struct bnxt *bp,\n+int bnxt_hwrm_set_l2_filter(struct bnxt *bp,\n \t\t\t uint16_t dst_id,\n \t\t\t struct bnxt_filter_info *filter);\n int bnxt_hwrm_exec_fwd_resp(struct bnxt *bp, uint16_t target_id,\n@@ -156,4 +156,12 @@ int bnxt_hwrm_func_vf_vnic_query_and_config(struct bnxt *bp, uint16_t vf,\n int bnxt_hwrm_func_cfg_vf_set_vlan_anti_spoof(struct bnxt *bp, uint16_t vf,\n \t\t\t\t\t      bool on);\n int bnxt_hwrm_func_qcfg_vf_dflt_vnic_id(struct bnxt *bp, int vf);\n+int bnxt_hwrm_set_em_filter(struct bnxt *bp, uint16_t dst_id,\n+\t\t\tstruct bnxt_filter_info *filter);\n+int bnxt_hwrm_clear_em_filter(struct bnxt *bp, struct bnxt_filter_info *filter);\n+\n+int bnxt_hwrm_set_ntuple_filter(struct bnxt *bp, uint16_t dst_id,\n+\t\t\t struct bnxt_filter_info *filter);\n+int bnxt_hwrm_clear_ntuple_filter(struct bnxt *bp,\n+\t\t\t\tstruct bnxt_filter_info *filter);\n #endif\ndiff --git a/drivers/net/bnxt/bnxt_vnic.c b/drivers/net/bnxt/bnxt_vnic.c\nindex db9fb0796..6f7c05bdf 100644\n--- a/drivers/net/bnxt/bnxt_vnic.c\n+++ b/drivers/net/bnxt/bnxt_vnic.c\n@@ -83,6 +83,7 @@ void bnxt_init_vnics(struct bnxt *bp)\n \n \t\tprandom_bytes(vnic->rss_hash_key, HW_HASH_KEY_SIZE);\n \t\tSTAILQ_INIT(&vnic->filter);\n+\t\tSTAILQ_INIT(&vnic->flow_list);\n \t\tSTAILQ_INSERT_TAIL(&bp->free_vnic_list, vnic, next);\n \t}\n \tfor (i = 0; i < MAX_FF_POOLS; i++)\ndiff --git a/drivers/net/bnxt/bnxt_vnic.h b/drivers/net/bnxt/bnxt_vnic.h\nindex 993f22127..544390453 100644\n--- a/drivers/net/bnxt/bnxt_vnic.h\n+++ b/drivers/net/bnxt/bnxt_vnic.h\n@@ -80,6 +80,7 @@ struct bnxt_vnic_info {\n \tbool\t\trss_dflt_cr;\n \n \tSTAILQ_HEAD(, bnxt_filter_info)\tfilter;\n+\tSTAILQ_HEAD(, rte_flow)\tflow_list;\n };\n \n struct bnxt;\ndiff --git a/drivers/net/bnxt/rte_pmd_bnxt.c b/drivers/net/bnxt/rte_pmd_bnxt.c\nindex 0bf5db5ec..82b9baca6 100644\n--- a/drivers/net/bnxt/rte_pmd_bnxt.c\n+++ b/drivers/net/bnxt/rte_pmd_bnxt.c\n@@ -730,7 +730,7 @@ int rte_pmd_bnxt_mac_addr_add(uint8_t port, struct ether_addr *addr,\n \t\t    (HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR |\n \t\t     HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR_MASK) &&\n \t\t    memcmp(addr, filter->l2_addr, ETHER_ADDR_LEN) == 0) {\n-\t\t\tbnxt_hwrm_clear_filter(bp, filter);\n+\t\t\tbnxt_hwrm_clear_l2_filter(bp, filter);\n \t\t\tbreak;\n \t\t}\n \t}\n@@ -748,7 +748,7 @@ int rte_pmd_bnxt_mac_addr_add(uint8_t port, struct ether_addr *addr,\n \t/* Do not add a filter for the default MAC */\n \tif (bnxt_hwrm_func_qcfg_vf_default_mac(bp, vf_id, &dflt_mac) ||\n \t    memcmp(filter->l2_addr, dflt_mac.addr_bytes, ETHER_ADDR_LEN))\n-\t\trc = bnxt_hwrm_set_filter(bp, vnic.fw_vnic_id, filter);\n+\t\trc = bnxt_hwrm_set_l2_filter(bp, vnic.fw_vnic_id, filter);\n \n exit:\n \treturn rc;\n",
    "prefixes": [
        "dpdk-dev",
        "v3",
        "18/24"
    ]
}