get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 35330,
    "url": "http://patches.dpdk.org/api/patches/35330/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1519222460-14605-6-git-send-email-tdu@semihalf.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1519222460-14605-6-git-send-email-tdu@semihalf.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1519222460-14605-6-git-send-email-tdu@semihalf.com",
    "date": "2018-02-21T14:14:17",
    "name": "[dpdk-dev,5/8] net/mrvl: add classifier support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "1d7c2f339984d42434e31a7cb618f71a90fd106b",
    "submitter": {
        "id": 846,
        "url": "http://patches.dpdk.org/api/people/846/?format=api",
        "name": "Tomasz Duszynski",
        "email": "tdu@semihalf.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1519222460-14605-6-git-send-email-tdu@semihalf.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/35330/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/35330/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 174761B2BA;\n\tWed, 21 Feb 2018 15:14:44 +0100 (CET)",
            "from mail-lf0-f68.google.com (mail-lf0-f68.google.com\n\t[209.85.215.68]) by dpdk.org (Postfix) with ESMTP id 014C11B1D9\n\tfor <dev@dpdk.org>; Wed, 21 Feb 2018 15:14:41 +0100 (CET)",
            "by mail-lf0-f68.google.com with SMTP id x196so2546348lfd.12\n\tfor <dev@dpdk.org>; Wed, 21 Feb 2018 06:14:40 -0800 (PST)",
            "from sh.semihalf.local (31-172-191-173.noc.fibertech.net.pl.\n\t[31.172.191.173]) by smtp.gmail.com with ESMTPSA id\n\te27sm5038177lff.89.2018.02.21.06.14.36\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tWed, 21 Feb 2018 06:14:37 -0800 (PST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=semihalf-com.20150623.gappssmtp.com; s=20150623;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references;\n\tbh=tSg0lE9heV0bD06RaJMjNMTOZJoVi56lwJ16pvm3+TY=;\n\tb=EOUMauaaawuJbWM2ipkTh58iGd3tcAwUyEO4hllTGmRYdJXxhf93/UbFwpi9Rj595F\n\tXcHV0zx5YzZs6l1lM+hMgMnAI8ssJv4ulQrSvBdXjVvxhp0ewZMjW5IGiTQ2v9CcPJmS\n\tugPOQcCOQxP0PGXYQUknkeBXfgY/M0yvooYhOoU2Scm09A7/m6LmqfaCnrxQPlYfXsk3\n\tortqhixEzv/PgaE2NGAIvF3nJpYa83PXxPIM5Ai14YgwOleJtHtvXS+76ovohrZvGPR5\n\tC5lcirMDNwP6vyQwgEyhKYO8BIwcBmY8jKQ74xaENWg4CbAAmbMkcsYUIw10lt8SMQGd\n\tkJSg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=tSg0lE9heV0bD06RaJMjNMTOZJoVi56lwJ16pvm3+TY=;\n\tb=ARABSieekQ4zlswSI6EFULD5Bli8xgDt6reBSfC/CmenLSWxIe9b9YPqTfU97jj5jj\n\t6xyyOavEj67TlTP89+oUbh8ok70Nlw/3puYpZCp3R1mG8DzwaXKSsxfsWKtTJbJPjrhd\n\tTeAmgZVTPDr7+wPtHT59d3MuxIrWGq31H4RIwE8dnEcZXCUnckjVfXxZU1r08iKh9uMA\n\t5q44na2lRsJ4jtzRrU2Q1nJrXp9pCc35Rl30479SIXPU33dedq5WkhPCSO2NL7sjIdEQ\n\tJ+bhfXguxcIyOG6WQxufnRZx9HHrCzurtdq+68wsOsvHF3baNynPULXi6zuIY5yYeQRQ\n\t4FIA==",
        "X-Gm-Message-State": "APf1xPCDLycff0IQrU+FW7b5CQygiRpHKyrchrpSosJF/TazpwvR8YDm\n\trcl5OttPIGO9DEf3f3cpP6+asB6S7EY=",
        "X-Google-Smtp-Source": "AH8x227v1XG/zVMYAohMvf/K1ByiuhsZxG23g8AzAyHMhBXs3oxclQxQc3fWoXD7DO30bc2FGNBm+A==",
        "X-Received": "by 10.25.34.81 with SMTP id i78mr2532019lfi.50.1519222477783;\n\tWed, 21 Feb 2018 06:14:37 -0800 (PST)",
        "From": "Tomasz Duszynski <tdu@semihalf.com>",
        "To": "dev@dpdk.org",
        "Cc": "mw@semihalf.com, dima@marvell.com, nsamsono@marvell.com, jck@semihalf.com,\n\tTomasz Duszynski <tdu@semihalf.com>",
        "Date": "Wed, 21 Feb 2018 15:14:17 +0100",
        "Message-Id": "<1519222460-14605-6-git-send-email-tdu@semihalf.com>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1519222460-14605-1-git-send-email-tdu@semihalf.com>",
        "References": "<1519222460-14605-1-git-send-email-tdu@semihalf.com>",
        "Subject": "[dpdk-dev] [PATCH 5/8] net/mrvl: add classifier support",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://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": "<https://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": "Add classifier configuration support via rte_flow api.\n\nSigned-off-by: Natalie Samsonov <nsamsono@marvell.com>\nSigned-off-by: Tomasz Duszynski <tdu@semihalf.com>\n---\n doc/guides/nics/mrvl.rst       |  168 +++\n drivers/net/mrvl/Makefile      |    1 +\n drivers/net/mrvl/mrvl_ethdev.c |   59 +\n drivers/net/mrvl/mrvl_ethdev.h |   10 +\n drivers/net/mrvl/mrvl_flow.c   | 2787 ++++++++++++++++++++++++++++++++++++++++\n 5 files changed, 3025 insertions(+)\n create mode 100644 drivers/net/mrvl/mrvl_flow.c",
    "diff": "diff --git a/doc/guides/nics/mrvl.rst b/doc/guides/nics/mrvl.rst\nindex 6794cbb..9230d5e 100644\n--- a/doc/guides/nics/mrvl.rst\n+++ b/doc/guides/nics/mrvl.rst\n@@ -113,6 +113,9 @@ Prerequisites\n   approval has been granted, library can be found by typing ``musdk`` in\n   the search box.\n \n+  To get better understanding of the library one can consult documentation\n+  available in the ``doc`` top level directory of the MUSDK sources.\n+\n   MUSDK must be configured with the following features:\n \n   .. code-block:: console\n@@ -318,6 +321,171 @@ the path to the MUSDK installation directory needs to be exported.\n    sed -ri 's,(MRVL_PMD=)n,\\1y,' build/.config\n    make\n \n+Flow API\n+--------\n+\n+PPv2 offers packet classification capabilities via classifier engine which\n+can be configured via generic flow API offered by DPDK.\n+\n+Supported flow actions\n+~~~~~~~~~~~~~~~~~~~~~~\n+\n+Following flow action items are supported by the driver:\n+\n+* DROP\n+* QUEUE\n+\n+Supported flow items\n+~~~~~~~~~~~~~~~~~~~~\n+\n+Following flow items and their respective fields are supported by the driver:\n+\n+* ETH\n+\n+  * source MAC\n+  * destination MAC\n+  * ethertype\n+\n+* VLAN\n+\n+  * PCP\n+  * VID\n+\n+* IPV4\n+\n+  * DSCP\n+  * protocol\n+  * source address\n+  * destination address\n+\n+* IPV6\n+\n+  * flow label\n+  * next header\n+  * source address\n+  * destination address\n+\n+* UDP\n+\n+  * source port\n+  * destination port\n+\n+* TCP\n+\n+  * source port\n+  * destination port\n+\n+Classifier match engine\n+~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Classifier has an internal match engine which can be configured to\n+operate in either exact or maskable mode.\n+\n+Mode is selected upon creation of the first unique flow rule as follows:\n+\n+* maskable, if key size is up to 8 bytes.\n+* exact, otherwise, i.e for keys bigger than 8 bytes.\n+\n+Where the key size equals the number of bytes of all fields specified\n+in the flow items.\n+\n+.. table:: Examples of key size calculation\n+\n+   +----------------------------------------------------------------------------+-------------------+-------------+\n+   | Flow pattern                                                               | Key size in bytes | Used engine |\n+   +============================================================================+===================+=============+\n+   | ETH (destination MAC) / VLAN (VID)                                         | 6 + 2 = 8         | Maskable    |\n+   +----------------------------------------------------------------------------+-------------------+-------------+\n+   | VLAN (VID) / IPV4 (source address)                                         | 2 + 4 = 6         | Maskable    |\n+   +----------------------------------------------------------------------------+-------------------+-------------+\n+   | TCP (source port, destination port)                                        | 2 + 2 = 4         | Maskable    |\n+   +----------------------------------------------------------------------------+-------------------+-------------+\n+   | VLAN (priority) / IPV4 (source address)                                    | 1 + 4 = 5         | Maskable    |\n+   +----------------------------------------------------------------------------+-------------------+-------------+\n+   | IPV4 (destination address) / UDP (source port, destination port)           | 6 + 2 + 2 = 10    | Exact       |\n+   +----------------------------------------------------------------------------+-------------------+-------------+\n+   | VLAN (VID) / IPV6 (flow label, destination address)                        | 2 + 3 + 16 = 21   | Exact       |\n+   +----------------------------------------------------------------------------+-------------------+-------------+\n+   | IPV4 (DSCP, source address, destination address)                           | 1 + 4 + 4 = 9     | Exact       |\n+   +----------------------------------------------------------------------------+-------------------+-------------+\n+   | IPV6 (flow label, source address, destination address)                     | 3 + 16 + 16 = 35  | Exact       |\n+   +----------------------------------------------------------------------------+-------------------+-------------+\n+\n+From the user perspective maskable mode means that masks specified\n+via flow rules are respected. In case of exact match mode, masks\n+which do not provide exact matching (all bits masked) are ignored.\n+\n+If the flow matches more than one classifier rule the first\n+(with the lowest index) matched takes precedence.\n+\n+Flow rules usage example\n+~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Before proceeding run testpmd user application:\n+\n+.. code-block:: console\n+\n+   ./testpmd --vdev=net_mrvl,iface=eth0,iface=eth2 -c 3 -- -i --p 3 -a --disable-hw-vlan-strip\n+\n+Example #1\n+^^^^^^^^^^\n+\n+.. code-block:: console\n+\n+   testpmd> flow create 0 ingress pattern eth src is 10:11:12:13:14:15 / end actions drop / end\n+\n+In this case key size is 6 bytes thus maskable type is selected. Testpmd\n+will set mask to ff:ff:ff:ff:ff:ff i.e traffic explicitly matching\n+above rule will be dropped.\n+\n+Example #2\n+^^^^^^^^^^\n+\n+.. code-block:: console\n+\n+   testpmd> flow create 0 ingress pattern ipv4 src spec 10.10.10.0 src mask 255.255.255.0 / tcp src spec 0x10 src mask 0x10 / end action drop / end\n+\n+In this case key size is 8 bytes thus maskable type is selected.\n+Flows which have IPv4 source addresses ranging from 10.10.10.0 to 10.10.10.255\n+and tcp source port set to 16 will be dropped.\n+\n+Example #3\n+^^^^^^^^^^\n+\n+.. code-block:: console\n+\n+   testpmd> flow create 0 ingress pattern vlan vid spec 0x10 vid mask 0x10 / ipv4 src spec 10.10.1.1 src mask 255.255.0.0 dst spec 11.11.11.1 dst mask 255.255.255.0 / end actions drop / end\n+\n+In this case key size is 10 bytes thus exact type is selected.\n+Even though each item has partial mask set, masks will be ignored.\n+As a result only flows with VID set to 16 and IPv4 source and destination\n+addresses set to 10.10.1.1 and 11.11.11.1 respectively will be dropped.\n+\n+Limitations\n+~~~~~~~~~~~\n+\n+Following limitations need to be taken into account while creating flow rules:\n+\n+* For IPv4 exact match type the key size must be up to 12 bytes.\n+* For IPv6 exact match type the key size must be up to 36 bytes.\n+* Following fields cannot be partially masked (all masks are treated as\n+  if they were exact):\n+\n+  * ETH: ethertype\n+  * VLAN: PCP, VID\n+  * IPv4: protocol\n+  * IPv6: next header\n+  * TCP/UDP: source port, destination port\n+\n+* Only one classifier table can be created thus all rules in the table\n+  have to match table format. Table format is set during creation of\n+  the first unique flow rule.\n+* Up to 5 fields can be specified per flow rule.\n+* Up to 20 flow rules can be added.\n+\n+For additional information about classifier please consult\n+``doc/musdk_cls_user_guide.txt``.\n+\n Usage Example\n -------------\n \ndiff --git a/drivers/net/mrvl/Makefile b/drivers/net/mrvl/Makefile\nindex f75e53c..8e7079f 100644\n--- a/drivers/net/mrvl/Makefile\n+++ b/drivers/net/mrvl/Makefile\n@@ -64,5 +64,6 @@ LDLIBS += -lrte_bus_vdev\n # library source files\n SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_ethdev.c\n SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_qos.c\n+SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_flow.c\n \n include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c\nindex e42b787..2536ee5 100644\n--- a/drivers/net/mrvl/mrvl_ethdev.c\n+++ b/drivers/net/mrvl/mrvl_ethdev.c\n@@ -687,6 +687,10 @@ mrvl_dev_stop(struct rte_eth_dev *dev)\n \tmrvl_dev_set_link_down(dev);\n \tmrvl_flush_rx_queues(dev);\n \tmrvl_flush_tx_shadow_queues(dev);\n+\tif (priv->cls_tbl) {\n+\t\tpp2_cls_tbl_deinit(priv->cls_tbl);\n+\t\tpriv->cls_tbl = NULL;\n+\t}\n \tif (priv->qos_tbl) {\n \t\tpp2_cls_qos_tbl_deinit(priv->qos_tbl);\n \t\tpriv->qos_tbl = NULL;\n@@ -812,6 +816,9 @@ mrvl_promiscuous_enable(struct rte_eth_dev *dev)\n \tif (!priv->ppio)\n \t\treturn;\n \n+\tif (priv->isolated)\n+\t\treturn;\n+\n \tret = pp2_ppio_set_promisc(priv->ppio, 1);\n \tif (ret)\n \t\tRTE_LOG(ERR, PMD, \"Failed to enable promiscuous mode\\n\");\n@@ -832,6 +839,9 @@ mrvl_allmulticast_enable(struct rte_eth_dev *dev)\n \tif (!priv->ppio)\n \t\treturn;\n \n+\tif (priv->isolated)\n+\t\treturn;\n+\n \tret = pp2_ppio_set_mc_promisc(priv->ppio, 1);\n \tif (ret)\n \t\tRTE_LOG(ERR, PMD, \"Failed enable all-multicast mode\\n\");\n@@ -895,6 +905,9 @@ mrvl_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)\n \tif (!priv->ppio)\n \t\treturn;\n \n+\tif (priv->isolated)\n+\t\treturn;\n+\n \tret = pp2_ppio_remove_mac_addr(priv->ppio,\n \t\t\t\t       dev->data->mac_addrs[index].addr_bytes);\n \tif (ret) {\n@@ -927,6 +940,9 @@ mrvl_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,\n \tchar buf[ETHER_ADDR_FMT_SIZE];\n \tint ret;\n \n+\tif (priv->isolated)\n+\t\treturn -ENOTSUP;\n+\n \tif (index == 0)\n \t\t/* For setting index 0, mrvl_mac_addr_set() should be used.*/\n \t\treturn -1;\n@@ -974,6 +990,9 @@ mrvl_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)\n \tif (!priv->ppio)\n \t\treturn;\n \n+\tif (priv->isolated)\n+\t\treturn;\n+\n \tret = pp2_ppio_set_mac_addr(priv->ppio, mac_addr->addr_bytes);\n \tif (ret) {\n \t\tchar buf[ETHER_ADDR_FMT_SIZE];\n@@ -1255,6 +1274,9 @@ mrvl_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)\n \tif (!priv->ppio)\n \t\treturn -EPERM;\n \n+\tif (priv->isolated)\n+\t\treturn -ENOTSUP;\n+\n \treturn on ? pp2_ppio_add_vlan(priv->ppio, vlan_id) :\n \t\t    pp2_ppio_remove_vlan(priv->ppio, vlan_id);\n }\n@@ -1608,6 +1630,9 @@ mrvl_rss_hash_update(struct rte_eth_dev *dev,\n {\n \tstruct mrvl_priv *priv = dev->data->dev_private;\n \n+\tif (priv->isolated)\n+\t\treturn -ENOTSUP;\n+\n \treturn mrvl_configure_rss(priv, rss_conf);\n }\n \n@@ -1644,6 +1669,39 @@ mrvl_rss_hash_conf_get(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+/**\n+ * DPDK callback to get rte_flow callbacks.\n+ *\n+ * @param dev\n+ *   Pointer to the device structure.\n+ * @param filer_type\n+ *   Flow filter type.\n+ * @param filter_op\n+ *   Flow filter operation.\n+ * @param arg\n+ *   Pointer to pass the flow ops.\n+ *\n+ * @return\n+ *   0 on success, negative error value otherwise.\n+ */\n+static int\n+mrvl_eth_filter_ctrl(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+\tswitch (filter_type) {\n+\tcase RTE_ETH_FILTER_GENERIC:\n+\t\tif (filter_op != RTE_ETH_FILTER_GET)\n+\t\t\treturn -EINVAL;\n+\t\t*(const void **)arg = &mrvl_flow_ops;\n+\t\treturn 0;\n+\tdefault:\n+\t\tRTE_LOG(WARNING, PMD, \"Filter type (%d) not supported\",\n+\t\t\t\tfilter_type);\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n static const struct eth_dev_ops mrvl_ops = {\n \t.dev_configure = mrvl_dev_configure,\n \t.dev_start = mrvl_dev_start,\n@@ -1673,6 +1731,7 @@ static const struct eth_dev_ops mrvl_ops = {\n \t.tx_queue_release = mrvl_tx_queue_release,\n \t.rss_hash_update = mrvl_rss_hash_update,\n \t.rss_hash_conf_get = mrvl_rss_hash_conf_get,\n+\t.filter_ctrl = mrvl_eth_filter_ctrl\n };\n \n /**\ndiff --git a/drivers/net/mrvl/mrvl_ethdev.h b/drivers/net/mrvl/mrvl_ethdev.h\nindex 0d152d6..c09f313 100644\n--- a/drivers/net/mrvl/mrvl_ethdev.h\n+++ b/drivers/net/mrvl/mrvl_ethdev.h\n@@ -36,6 +36,7 @@\n #define _MRVL_ETHDEV_H_\n \n #include <rte_spinlock.h>\n+#include <rte_flow_driver.h>\n \n #include <env/mv_autogen_comp_flags.h>\n #include <drivers/mv_pp2.h>\n@@ -108,12 +109,21 @@ struct mrvl_priv {\n \tuint8_t rss_hf_tcp;\n \tuint8_t uc_mc_flushed;\n \tuint8_t vlan_flushed;\n+\tuint8_t isolated;\n \n \tstruct pp2_ppio_params ppio_params;\n \tstruct pp2_cls_qos_tbl_params qos_tbl_params;\n \tstruct pp2_cls_tbl *qos_tbl;\n \tuint16_t nb_rx_queues;\n+\n+\tstruct pp2_cls_tbl_params cls_tbl_params;\n+\tstruct pp2_cls_tbl *cls_tbl;\n+\tuint32_t cls_tbl_pattern;\n+\tLIST_HEAD(mrvl_flows, rte_flow) flows;\n+\n \tstruct pp2_cls_plcr *policer;\n };\n \n+/** Flow operations forward declaration. */\n+extern const struct rte_flow_ops mrvl_flow_ops;\n #endif /* _MRVL_ETHDEV_H_ */\ndiff --git a/drivers/net/mrvl/mrvl_flow.c b/drivers/net/mrvl/mrvl_flow.c\nnew file mode 100644\nindex 0000000..a2c25e6\n--- /dev/null\n+++ b/drivers/net/mrvl/mrvl_flow.c\n@@ -0,0 +1,2787 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2018 Marvell International Ltd.\n+ *   Copyright(c) 2018 Semihalf.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of the copyright holder nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <rte_flow.h>\n+#include <rte_flow_driver.h>\n+#include <rte_malloc.h>\n+#include <rte_log.h>\n+\n+#include <arpa/inet.h>\n+\n+#ifdef container_of\n+#undef container_of\n+#endif\n+\n+#include \"mrvl_ethdev.h\"\n+#include \"mrvl_qos.h\"\n+#include \"env/mv_common.h\" /* for BIT() */\n+\n+/** Number of rules in the classifier table. */\n+#define MRVL_CLS_MAX_NUM_RULES 20\n+\n+/** Size of the classifier key and mask strings. */\n+#define MRVL_CLS_STR_SIZE_MAX 40\n+\n+/** Parsed fields in processed rte_flow_item. */\n+enum mrvl_parsed_fields {\n+\t/* eth flags */\n+\tF_DMAC =         BIT(0),\n+\tF_SMAC =         BIT(1),\n+\tF_TYPE =         BIT(2),\n+\t/* vlan flags */\n+\tF_VLAN_ID =      BIT(3),\n+\tF_VLAN_PRI =     BIT(4),\n+\tF_VLAN_TCI =     BIT(5), /* not supported by MUSDK yet */\n+\t/* ip4 flags */\n+\tF_IP4_TOS =      BIT(6),\n+\tF_IP4_SIP =      BIT(7),\n+\tF_IP4_DIP =      BIT(8),\n+\tF_IP4_PROTO =    BIT(9),\n+\t/* ip6 flags */\n+\tF_IP6_TC =       BIT(10), /* not supported by MUSDK yet */\n+\tF_IP6_SIP =      BIT(11),\n+\tF_IP6_DIP =      BIT(12),\n+\tF_IP6_FLOW =     BIT(13),\n+\tF_IP6_NEXT_HDR = BIT(14),\n+\t/* tcp flags */\n+\tF_TCP_SPORT =    BIT(15),\n+\tF_TCP_DPORT =    BIT(16),\n+\t/* udp flags */\n+\tF_UDP_SPORT =    BIT(17),\n+\tF_UDP_DPORT =    BIT(18),\n+};\n+\n+/** PMD-specific definition of a flow rule handle. */\n+struct rte_flow {\n+\tLIST_ENTRY(rte_flow) next;\n+\n+\tenum mrvl_parsed_fields pattern;\n+\n+\tstruct pp2_cls_tbl_rule rule;\n+\tstruct pp2_cls_cos_desc cos;\n+\tstruct pp2_cls_tbl_action action;\n+};\n+\n+static const enum rte_flow_item_type pattern_eth[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_eth_vlan[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_eth_vlan_ip[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_eth_vlan_ip6[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_eth_ip4[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_eth_ip4_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 const enum rte_flow_item_type pattern_eth_ip4_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 const enum rte_flow_item_type pattern_eth_ip6[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_eth_ip6_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+static const enum rte_flow_item_type pattern_eth_ip6_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 const enum rte_flow_item_type pattern_vlan[] = {\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_vlan_ip[] = {\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_vlan_ip_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_vlan_ip_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_vlan_ip6[] = {\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_vlan_ip6_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_vlan_ip6_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_ip[] = {\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_ip6[] = {\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_ip_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_ip6_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_ip_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_IPV4,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_ip6_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_IPV6,\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_tcp[] = {\n+\tRTE_FLOW_ITEM_TYPE_TCP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+static const enum rte_flow_item_type pattern_udp[] = {\n+\tRTE_FLOW_ITEM_TYPE_UDP,\n+\tRTE_FLOW_ITEM_TYPE_END\n+};\n+\n+#define MRVL_VLAN_ID_MASK 0x0fff\n+#define MRVL_VLAN_PRI_MASK 0x7000\n+#define MRVL_IPV4_DSCP_MASK 0xfc\n+#define MRVL_IPV4_ADDR_MASK 0xffffffff\n+#define MRVL_IPV6_FLOW_MASK 0x0fffff\n+\n+/**\n+ * Given a flow item, return the next non-void one.\n+ *\n+ * @param items Pointer to the item in the table.\n+ * @returns Next not-void item, NULL otherwise.\n+ */\n+static const struct rte_flow_item *\n+mrvl_next_item(const struct rte_flow_item *items)\n+{\n+\tconst struct rte_flow_item *item = items;\n+\n+\tfor (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (item->type != RTE_FLOW_ITEM_TYPE_VOID)\n+\t\t\treturn item;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+/**\n+ * Allocate memory for classifier rule key and mask fields.\n+ *\n+ * @param field Pointer to the classifier rule.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_alloc_key_mask(struct pp2_cls_rule_key_field *field)\n+{\n+\tunsigned int id = rte_socket_id();\n+\n+\tfield->key = rte_zmalloc_socket(NULL, MRVL_CLS_STR_SIZE_MAX, 0, id);\n+\tif (!field->key)\n+\t\tgoto out;\n+\n+\tfield->mask = rte_zmalloc_socket(NULL, MRVL_CLS_STR_SIZE_MAX, 0, id);\n+\tif (!field->mask)\n+\t\tgoto out_mask;\n+\n+\treturn 0;\n+out_mask:\n+\trte_free(field->key);\n+out:\n+\tfield->key = NULL;\n+\tfield->mask = NULL;\n+\treturn -1;\n+}\n+\n+/**\n+ * Free memory allocated for classifier rule key and mask fields.\n+ *\n+ * @param field Pointer to the classifier rule.\n+ */\n+static void\n+mrvl_free_key_mask(struct pp2_cls_rule_key_field *field)\n+{\n+\trte_free(field->key);\n+\trte_free(field->mask);\n+\tfield->key = NULL;\n+\tfield->mask = NULL;\n+}\n+\n+/**\n+ * Free memory allocated for all classifier rule key and mask fields.\n+ *\n+ * @param rule Pointer to the classifier table rule.\n+ */\n+static void\n+mrvl_free_all_key_mask(struct pp2_cls_tbl_rule *rule)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < rule->num_fields; i++)\n+\t\tmrvl_free_key_mask(&rule->fields[i]);\n+\trule->num_fields = 0;\n+}\n+\n+/*\n+ * Initialize rte flow item parsing.\n+ *\n+ * @param item Pointer to the flow item.\n+ * @param spec_ptr Pointer to the specific item pointer.\n+ * @param mask_ptr Pointer to the specific item's mask pointer.\n+ * @def_mask Pointer to the default mask.\n+ * @size Size of the flow item.\n+ * @error Pointer to the rte flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_init(const struct rte_flow_item *item,\n+\t\tconst void **spec_ptr,\n+\t\tconst void **mask_ptr,\n+\t\tconst void *def_mask,\n+\t\tunsigned int size,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst uint8_t *spec;\n+\tconst uint8_t *mask;\n+\tconst uint8_t *last;\n+\tuint8_t zeros[size];\n+\n+\tmemset(zeros, 0, size);\n+\n+\tif (item == NULL) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM, NULL,\n+\t\t\t\t   \"NULL item\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif ((item->last != NULL || item->mask != NULL) && item->spec == NULL) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t   \"Mask or last is set without spec\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\t/*\n+\t * If \"mask\" is not set, default mask is used,\n+\t * but if default mask is NULL, \"mask\" should be set.\n+\t */\n+\tif (item->mask == NULL) {\n+\t\tif (def_mask == NULL) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM, NULL,\n+\t\t\t\t\t   \"Mask should be specified\\n\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t\tmask = (const uint8_t *)def_mask;\n+\t} else {\n+\t\tmask = (const uint8_t *)item->mask;\n+\t}\n+\n+\tspec = (const uint8_t *)item->spec;\n+\tlast = (const uint8_t *)item->last;\n+\n+\tif (spec == NULL) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t   NULL, \"Spec should be specified\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\t/*\n+\t * If field values in \"last\" are either 0 or equal to the corresponding\n+\t * values in \"spec\" then they are ignored.\n+\t */\n+\tif (last != NULL &&\n+\t    !memcmp(last, zeros, size) &&\n+\t    memcmp(last, spec, size) != 0) {\n+\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM, NULL,\n+\t\t\t\t   \"Ranging is not supported\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\t*spec_ptr = spec;\n+\t*mask_ptr = mask;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse the eth flow item.\n+ *\n+ * This will create classifier rule that matches either destination or source\n+ * mac.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param mask Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_mac(const struct rte_flow_item_eth *spec,\n+\t       const struct rte_flow_item_eth *mask,\n+\t       int parse_dst, struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tconst uint8_t *k, *m;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tif (parse_dst) {\n+\t\tk = spec->dst.addr_bytes;\n+\t\tm = mask->dst.addr_bytes;\n+\n+\t\tflow->pattern |= F_DMAC;\n+\t} else {\n+\t\tk = spec->src.addr_bytes;\n+\t\tm = mask->src.addr_bytes;\n+\n+\t\tflow->pattern |= F_SMAC;\n+\t}\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 6;\n+\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX,\n+\t\t \"%02x:%02x:%02x:%02x:%02x:%02x\",\n+\t\t k[0], k[1], k[2], k[3], k[4], k[5]);\n+\n+\tsnprintf((char *)key_field->mask, MRVL_CLS_STR_SIZE_MAX,\n+\t\t \"%02x:%02x:%02x:%02x:%02x:%02x\",\n+\t\t m[0], m[1], m[2], m[3], m[4], m[5]);\n+\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Helper for parsing the eth flow item destination mac address.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_dmac(const struct rte_flow_item_eth *spec,\n+\t\tconst struct rte_flow_item_eth *mask,\n+\t\tstruct rte_flow *flow)\n+{\n+\treturn mrvl_parse_mac(spec, mask, 1, flow);\n+}\n+\n+/**\n+ * Helper for parsing the eth flow item source mac address.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_smac(const struct rte_flow_item_eth *spec,\n+\t\tconst struct rte_flow_item_eth *mask,\n+\t\tstruct rte_flow *flow)\n+{\n+\treturn mrvl_parse_mac(spec, mask, 0, flow);\n+}\n+\n+/**\n+ * Parse the ether type field of the eth flow item.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_type(const struct rte_flow_item_eth *spec,\n+\t\tconst struct rte_flow_item_eth *mask __rte_unused,\n+\t\tstruct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tuint16_t k;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 2;\n+\n+\tk = rte_be_to_cpu_16(spec->type);\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX, \"%u\", k);\n+\n+\tflow->pattern |= F_TYPE;\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse the vid field of the vlan rte flow item.\n+ *\n+ * This will create classifier rule that matches vid.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_vlan_id(const struct rte_flow_item_vlan *spec,\n+\t\t   const struct rte_flow_item_vlan *mask __rte_unused,\n+\t\t   struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tuint16_t k;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 2;\n+\n+\tk = rte_be_to_cpu_16(spec->tci) & MRVL_VLAN_ID_MASK;\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX, \"%u\", k);\n+\n+\tflow->pattern |= F_VLAN_ID;\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse the pri field of the vlan rte flow item.\n+ *\n+ * This will create classifier rule that matches pri.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_vlan_pri(const struct rte_flow_item_vlan *spec,\n+\t\t    const struct rte_flow_item_vlan *mask __rte_unused,\n+\t\t    struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tuint16_t k;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 1;\n+\n+\tk = (rte_be_to_cpu_16(spec->tci) & MRVL_VLAN_PRI_MASK) >> 13;\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX, \"%u\", k);\n+\n+\tflow->pattern |= F_VLAN_PRI;\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse the dscp field of the ipv4 rte flow item.\n+ *\n+ * This will create classifier rule that matches dscp field.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_ip4_dscp(const struct rte_flow_item_ipv4 *spec,\n+\t\t    const struct rte_flow_item_ipv4 *mask,\n+\t\t    struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tuint8_t k, m;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 1;\n+\n+\tk = (spec->hdr.type_of_service & MRVL_IPV4_DSCP_MASK) >> 2;\n+\tm = (mask->hdr.type_of_service & MRVL_IPV4_DSCP_MASK) >> 2;\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX, \"%u\", k);\n+\tsnprintf((char *)key_field->mask, MRVL_CLS_STR_SIZE_MAX, \"%u\", m);\n+\n+\tflow->pattern |= F_IP4_TOS;\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse either source or destination ip addresses of the ipv4 flow item.\n+ *\n+ * This will create classifier rule that matches either destination\n+ * or source ip field.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_ip4_addr(const struct rte_flow_item_ipv4 *spec,\n+\t\t    const struct rte_flow_item_ipv4 *mask,\n+\t\t    int parse_dst, struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tstruct in_addr k;\n+\tuint32_t m;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tmemset(&k, 0, sizeof(k));\n+\tif (parse_dst) {\n+\t\tk.s_addr = spec->hdr.dst_addr;\n+\t\tm = rte_be_to_cpu_32(mask->hdr.dst_addr);\n+\n+\t\tflow->pattern |= F_IP4_DIP;\n+\t} else {\n+\t\tk.s_addr = spec->hdr.src_addr;\n+\t\tm = rte_be_to_cpu_32(mask->hdr.src_addr);\n+\n+\t\tflow->pattern |= F_IP4_SIP;\n+\t}\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 4;\n+\n+\tinet_ntop(AF_INET, &k, (char *)key_field->key, MRVL_CLS_STR_SIZE_MAX);\n+\tsnprintf((char *)key_field->mask, MRVL_CLS_STR_SIZE_MAX, \"0x%x\", m);\n+\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Helper for parsing destination ip of the ipv4 flow item.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_ip4_dip(const struct rte_flow_item_ipv4 *spec,\n+\t\t   const struct rte_flow_item_ipv4 *mask,\n+\t\t   struct rte_flow *flow)\n+{\n+\treturn mrvl_parse_ip4_addr(spec, mask, 1, flow);\n+}\n+\n+/**\n+ * Helper for parsing source ip of the ipv4 flow item.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_ip4_sip(const struct rte_flow_item_ipv4 *spec,\n+\t\t   const struct rte_flow_item_ipv4 *mask,\n+\t\t   struct rte_flow *flow)\n+{\n+\treturn mrvl_parse_ip4_addr(spec, mask, 0, flow);\n+}\n+\n+/**\n+ * Parse the proto field of the ipv4 rte flow item.\n+ *\n+ * This will create classifier rule that matches proto field.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_ip4_proto(const struct rte_flow_item_ipv4 *spec,\n+\t\t     const struct rte_flow_item_ipv4 *mask __rte_unused,\n+\t\t     struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tuint8_t k = spec->hdr.next_proto_id;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 1;\n+\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX, \"%u\", k);\n+\n+\tflow->pattern |= F_IP4_PROTO;\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse either source or destination ip addresses of the ipv6 rte flow item.\n+ *\n+ * This will create classifier rule that matches either destination\n+ * or source ip field.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_ip6_addr(const struct rte_flow_item_ipv6 *spec,\n+\t       const struct rte_flow_item_ipv6 *mask,\n+\t       int parse_dst, struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tint size = sizeof(spec->hdr.dst_addr);\n+\tstruct in6_addr k, m;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tmemset(&k, 0, sizeof(k));\n+\tif (parse_dst) {\n+\t\tmemcpy(k.s6_addr, spec->hdr.dst_addr, size);\n+\t\tmemcpy(m.s6_addr, mask->hdr.dst_addr, size);\n+\n+\t\tflow->pattern |= F_IP6_DIP;\n+\t} else {\n+\t\tmemcpy(k.s6_addr, spec->hdr.src_addr, size);\n+\t\tmemcpy(m.s6_addr, mask->hdr.src_addr, size);\n+\n+\t\tflow->pattern |= F_IP6_SIP;\n+\t}\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 16;\n+\n+\tinet_ntop(AF_INET6, &k, (char *)key_field->key, MRVL_CLS_STR_SIZE_MAX);\n+\tinet_ntop(AF_INET6, &m, (char *)key_field->mask, MRVL_CLS_STR_SIZE_MAX);\n+\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Helper for parsing destination ip of the ipv6 flow item.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_ip6_dip(const struct rte_flow_item_ipv6 *spec,\n+\t\t   const struct rte_flow_item_ipv6 *mask,\n+\t\t   struct rte_flow *flow)\n+{\n+\treturn mrvl_parse_ip6_addr(spec, mask, 1, flow);\n+}\n+\n+/**\n+ * Helper for parsing source ip of the ipv6 flow item.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_ip6_sip(const struct rte_flow_item_ipv6 *spec,\n+\t\t   const struct rte_flow_item_ipv6 *mask,\n+\t\t   struct rte_flow *flow)\n+{\n+\treturn mrvl_parse_ip6_addr(spec, mask, 0, flow);\n+}\n+\n+/**\n+ * Parse the flow label of the ipv6 flow item.\n+ *\n+ * This will create classifier rule that matches flow field.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_ip6_flow(const struct rte_flow_item_ipv6 *spec,\n+\t\t    const struct rte_flow_item_ipv6 *mask,\n+\t\t    struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tuint32_t k = rte_be_to_cpu_32(spec->hdr.vtc_flow) & MRVL_IPV6_FLOW_MASK,\n+\t\t m = rte_be_to_cpu_32(mask->hdr.vtc_flow) & MRVL_IPV6_FLOW_MASK;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 3;\n+\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX, \"%u\", k);\n+\tsnprintf((char *)key_field->mask, MRVL_CLS_STR_SIZE_MAX, \"%u\", m);\n+\n+\tflow->pattern |= F_IP6_FLOW;\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse the next header of the ipv6 flow item.\n+ *\n+ * This will create classifier rule that matches next header field.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_ip6_next_hdr(const struct rte_flow_item_ipv6 *spec,\n+\t\t\tconst struct rte_flow_item_ipv6 *mask __rte_unused,\n+\t\t\tstruct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tuint8_t k = spec->hdr.proto;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 1;\n+\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX, \"%u\", k);\n+\n+\tflow->pattern |= F_IP6_NEXT_HDR;\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse destination or source port of the tcp flow item.\n+ *\n+ * This will create classifier rule that matches either destination or\n+ * source tcp port.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_tcp_port(const struct rte_flow_item_tcp *spec,\n+\t\t    const struct rte_flow_item_tcp *mask __rte_unused,\n+\t\t    int parse_dst, struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tuint16_t k;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 2;\n+\n+\tif (parse_dst) {\n+\t\tk = rte_be_to_cpu_16(spec->hdr.dst_port);\n+\n+\t\tflow->pattern |= F_TCP_DPORT;\n+\t} else {\n+\t\tk = rte_be_to_cpu_16(spec->hdr.src_port);\n+\n+\t\tflow->pattern |= F_TCP_SPORT;\n+\t}\n+\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX, \"%u\", k);\n+\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Helper for parsing the tcp source port of the tcp flow item.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_tcp_sport(const struct rte_flow_item_tcp *spec,\n+\t\t     const struct rte_flow_item_tcp *mask,\n+\t\t     struct rte_flow *flow)\n+{\n+\treturn mrvl_parse_tcp_port(spec, mask, 0, flow);\n+}\n+\n+/**\n+ * Helper for parsing the tcp destination port of the tcp flow item.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_tcp_dport(const struct rte_flow_item_tcp *spec,\n+\t\t     const struct rte_flow_item_tcp *mask,\n+\t\t     struct rte_flow *flow)\n+{\n+\treturn mrvl_parse_tcp_port(spec, mask, 1, flow);\n+}\n+\n+/**\n+ * Parse destination or source port of the udp flow item.\n+ *\n+ * This will create classifier rule that matches either destination or\n+ * source udp port.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static int\n+mrvl_parse_udp_port(const struct rte_flow_item_udp *spec,\n+\t\t    const struct rte_flow_item_udp *mask __rte_unused,\n+\t\t    int parse_dst, struct rte_flow *flow)\n+{\n+\tstruct pp2_cls_rule_key_field *key_field;\n+\tuint16_t k;\n+\n+\tif (flow->rule.num_fields >= PP2_CLS_TBL_MAX_NUM_FIELDS)\n+\t\treturn -ENOSPC;\n+\n+\tkey_field = &flow->rule.fields[flow->rule.num_fields];\n+\tmrvl_alloc_key_mask(key_field);\n+\tkey_field->size = 2;\n+\n+\tif (parse_dst) {\n+\t\tk = rte_be_to_cpu_16(spec->hdr.dst_port);\n+\n+\t\tflow->pattern |= F_UDP_DPORT;\n+\t} else {\n+\t\tk = rte_be_to_cpu_16(spec->hdr.src_port);\n+\n+\t\tflow->pattern |= F_UDP_SPORT;\n+\t}\n+\n+\tsnprintf((char *)key_field->key, MRVL_CLS_STR_SIZE_MAX, \"%u\", k);\n+\n+\tflow->rule.num_fields += 1;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Helper for parsing the udp source port of the udp flow item.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_udp_sport(const struct rte_flow_item_udp *spec,\n+\t\t     const struct rte_flow_item_udp *mask,\n+\t\t     struct rte_flow *flow)\n+{\n+\treturn mrvl_parse_udp_port(spec, mask, 0, flow);\n+}\n+\n+/**\n+ * Helper for parsing the udp destination port of the udp flow item.\n+ *\n+ * @param spec Pointer to the specific flow item.\n+ * @param mask Pointer to the specific flow item's mask.\n+ * @param flow Pointer to the flow.\n+ * @return 0 in case of success, negative error value otherwise.\n+ */\n+static inline int\n+mrvl_parse_udp_dport(const struct rte_flow_item_udp *spec,\n+\t\t     const struct rte_flow_item_udp *mask,\n+\t\t     struct rte_flow *flow)\n+{\n+\treturn mrvl_parse_udp_port(spec, mask, 1, flow);\n+}\n+\n+/**\n+ * Parse eth flow item.\n+ *\n+ * @param item Pointer to the flow item.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param fields Pointer to the parsed parsed fields enum.\n+ * @returns 0 on success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_eth(const struct rte_flow_item *item, struct rte_flow *flow,\n+\t       struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_eth *spec = NULL, *mask = NULL;\n+\tstruct ether_addr zero;\n+\tint ret;\n+\n+\tret = mrvl_parse_init(item, (const void **)&spec, (const void **)&mask,\n+\t\t\t      &rte_flow_item_eth_mask,\n+\t\t\t      sizeof(struct rte_flow_item_eth), error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tmemset(&zero, 0, sizeof(zero));\n+\n+\tif (memcmp(&mask->dst, &zero, sizeof(mask->dst))) {\n+\t\tret = mrvl_parse_dmac(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (memcmp(&mask->src, &zero, sizeof(mask->src))) {\n+\t\tret = mrvl_parse_smac(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (mask->type) {\n+\t\tRTE_LOG(WARNING, PMD, \"eth type mask is ignored\\n\");\n+\t\tret = mrvl_parse_type(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\treturn 0;\n+out:\n+\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t   \"Reached maximum number of fields in cls tbl key\\n\");\n+\treturn -rte_errno;\n+}\n+\n+/**\n+ * Parse vlan flow item.\n+ *\n+ * @param item Pointer to the flow item.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param fields Pointer to the parsed parsed fields enum.\n+ * @returns 0 on success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_vlan(const struct rte_flow_item *item,\n+\t\tstruct rte_flow *flow,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_vlan *spec = NULL, *mask = NULL;\n+\tuint16_t m;\n+\tint ret;\n+\n+\tret = mrvl_parse_init(item, (const void **)&spec, (const void **)&mask,\n+\t\t\t      &rte_flow_item_vlan_mask,\n+\t\t\t      sizeof(struct rte_flow_item_vlan), error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (mask->tpid) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t   NULL, \"Not supported by classifier\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tm = rte_be_to_cpu_16(mask->tci);\n+\tif (m & MRVL_VLAN_ID_MASK) {\n+\t\tRTE_LOG(WARNING, PMD, \"vlan id mask is ignored\\n\");\n+\t\tret = mrvl_parse_vlan_id(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (m & MRVL_VLAN_PRI_MASK) {\n+\t\tRTE_LOG(WARNING, PMD, \"vlan pri mask is ignored\\n\");\n+\t\tret = mrvl_parse_vlan_pri(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\treturn 0;\n+out:\n+\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t   \"Reached maximum number of fields in cls tbl key\\n\");\n+\treturn -rte_errno;\n+}\n+\n+/**\n+ * Parse ipv4 flow item.\n+ *\n+ * @param item Pointer to the flow item.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param fields Pointer to the parsed parsed fields enum.\n+ * @returns 0 on success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_ip4(const struct rte_flow_item *item,\n+\t       struct rte_flow *flow,\n+\t       struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_ipv4 *spec = NULL, *mask = NULL;\n+\tint ret;\n+\n+\tret = mrvl_parse_init(item, (const void **)&spec, (const void **)&mask,\n+\t\t\t      &rte_flow_item_ipv4_mask,\n+\t\t\t      sizeof(struct rte_flow_item_ipv4), error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (mask->hdr.version_ihl ||\n+\t    mask->hdr.total_length ||\n+\t    mask->hdr.packet_id ||\n+\t    mask->hdr.fragment_offset ||\n+\t    mask->hdr.time_to_live ||\n+\t    mask->hdr.hdr_checksum) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t   NULL, \"Not supported by classifier\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (mask->hdr.type_of_service & MRVL_IPV4_DSCP_MASK) {\n+\t\tret = mrvl_parse_ip4_dscp(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (mask->hdr.src_addr) {\n+\t\tret = mrvl_parse_ip4_sip(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (mask->hdr.dst_addr) {\n+\t\tret = mrvl_parse_ip4_dip(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (mask->hdr.next_proto_id) {\n+\t\tRTE_LOG(WARNING, PMD, \"next proto id mask is ignored\\n\");\n+\t\tret = mrvl_parse_ip4_proto(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\treturn 0;\n+out:\n+\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t   \"Reached maximum number of fields in cls tbl key\\n\");\n+\treturn -rte_errno;\n+}\n+\n+/**\n+ * Parse ipv6 flow item.\n+ *\n+ * @param item Pointer to the flow item.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param fields Pointer to the parsed parsed fields enum.\n+ * @returns 0 on success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_ip6(const struct rte_flow_item *item,\n+\t       struct rte_flow *flow,\n+\t       struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_ipv6 *spec = NULL, *mask = NULL;\n+\tstruct ipv6_hdr zero;\n+\tuint32_t flow_mask;\n+\tint ret;\n+\n+\tret = mrvl_parse_init(item, (const void **)&spec,\n+\t\t\t      (const void **)&mask,\n+\t\t\t      &rte_flow_item_ipv6_mask,\n+\t\t\t      sizeof(struct rte_flow_item_ipv6),\n+\t\t\t      error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tmemset(&zero, 0, sizeof(zero));\n+\n+\tif (mask->hdr.payload_len ||\n+\t    mask->hdr.hop_limits) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t   NULL, \"Not supported by classifier\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (memcmp(mask->hdr.src_addr,\n+\t\t   zero.src_addr, sizeof(mask->hdr.src_addr))) {\n+\t\tret = mrvl_parse_ip6_sip(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (memcmp(mask->hdr.dst_addr,\n+\t\t   zero.dst_addr, sizeof(mask->hdr.dst_addr))) {\n+\t\tret = mrvl_parse_ip6_dip(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tflow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow) & MRVL_IPV6_FLOW_MASK;\n+\tif (flow_mask) {\n+\t\tret = mrvl_parse_ip6_flow(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (mask->hdr.proto) {\n+\t\tRTE_LOG(WARNING, PMD, \"next header mask is ignored\\n\");\n+\t\tret = mrvl_parse_ip6_next_hdr(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\treturn 0;\n+out:\n+\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t   \"Reached maximum number of fields in cls tbl key\\n\");\n+\treturn -rte_errno;\n+}\n+\n+/**\n+ * Parse tcp flow item.\n+ *\n+ * @param item Pointer to the flow item.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param fields Pointer to the parsed parsed fields enum.\n+ * @returns 0 on success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_tcp(const struct rte_flow_item *item,\n+\t       struct rte_flow *flow,\n+\t       struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_tcp *spec = NULL, *mask = NULL;\n+\tint ret;\n+\n+\tret = mrvl_parse_init(item, (const void **)&spec, (const void **)&mask,\n+\t\t\t      &rte_flow_item_ipv4_mask,\n+\t\t\t      sizeof(struct rte_flow_item_ipv4), error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (mask->hdr.sent_seq ||\n+\t    mask->hdr.recv_ack ||\n+\t    mask->hdr.data_off ||\n+\t    mask->hdr.tcp_flags ||\n+\t    mask->hdr.rx_win ||\n+\t    mask->hdr.cksum ||\n+\t    mask->hdr.tcp_urp) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t   NULL, \"Not supported by classifier\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (mask->hdr.src_port) {\n+\t\tRTE_LOG(WARNING, PMD, \"tcp sport mask is ignored\\n\");\n+\t\tret = mrvl_parse_tcp_sport(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (mask->hdr.dst_port) {\n+\t\tRTE_LOG(WARNING, PMD, \"tcp dport mask is ignored\\n\");\n+\t\tret = mrvl_parse_tcp_dport(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\treturn 0;\n+out:\n+\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t   \"Reached maximum number of fields in cls tbl key\\n\");\n+\treturn -rte_errno;\n+}\n+\n+/**\n+ * Parse udp flow item.\n+ *\n+ * @param item Pointer to the flow item.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param fields Pointer to the parsed parsed fields enum.\n+ * @returns 0 on success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_udp(const struct rte_flow_item *item,\n+\t       struct rte_flow *flow,\n+\t       struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item_udp *spec = NULL, *mask = NULL;\n+\tint ret;\n+\n+\tret = mrvl_parse_init(item, (const void **)&spec, (const void **)&mask,\n+\t\t\t      &rte_flow_item_ipv4_mask,\n+\t\t\t      sizeof(struct rte_flow_item_ipv4), error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (mask->hdr.dgram_len ||\n+\t    mask->hdr.dgram_cksum) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t   NULL, \"Not supported by classifier\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (mask->hdr.src_port) {\n+\t\tRTE_LOG(WARNING, PMD, \"udp sport mask is ignored\\n\");\n+\t\tret = mrvl_parse_udp_sport(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\tif (mask->hdr.dst_port) {\n+\t\tRTE_LOG(WARNING, PMD, \"udp dport mask is ignored\\n\");\n+\t\tret = mrvl_parse_udp_dport(spec, mask, flow);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t}\n+\n+\treturn 0;\n+out:\n+\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t   \"Reached maximum number of fields in cls tbl key\\n\");\n+\treturn -rte_errno;\n+}\n+\n+/**\n+ * Parse flow pattern composed of the the eth item.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_eth(const struct rte_flow_item pattern[],\n+\t\t       struct rte_flow *flow,\n+\t\t       struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_eth(pattern, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth and vlan items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_eth_vlan(const struct rte_flow_item pattern[],\n+\t\t\t    struct rte_flow *flow,\n+\t\t\t    struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = mrvl_parse_eth(item, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\n+\treturn mrvl_parse_vlan(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth, vlan and ip4/ip6 items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param ip6 1 to parse ip6 item, 0 to parse ip4 item.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_eth_vlan_ip4_ip6(const struct rte_flow_item pattern[],\n+\t\t\t\t    struct rte_flow *flow,\n+\t\t\t\t    struct rte_flow_error *error, int ip6)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = mrvl_parse_eth(item, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\tret = mrvl_parse_vlan(item, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\n+\treturn ip6 ? mrvl_parse_ip6(item, flow, error) :\n+\t\t     mrvl_parse_ip4(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth, vlan and ipv4 items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_eth_vlan_ip4(const struct rte_flow_item pattern[],\n+\t\t\t\tstruct rte_flow *flow,\n+\t\t\t\tstruct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_eth_vlan_ip4_ip6(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth, vlan and ipv6 items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_eth_vlan_ip6(const struct rte_flow_item pattern[],\n+\t\t\t\tstruct rte_flow *flow,\n+\t\t\t\tstruct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_eth_vlan_ip4_ip6(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth and ip4/ip6 items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param ip6 1 to parse ip6 item, 0 to parse ip4 item.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_eth_ip4_ip6(const struct rte_flow_item pattern[],\n+\t\t\t       struct rte_flow *flow,\n+\t\t\t       struct rte_flow_error *error, int ip6)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = mrvl_parse_eth(item, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\n+\treturn ip6 ? mrvl_parse_ip6(item, flow, error) :\n+\t\t     mrvl_parse_ip4(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth and ipv4 items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_eth_ip4(const struct rte_flow_item pattern[],\n+\t\t\t   struct rte_flow *flow,\n+\t\t\t   struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_eth_ip4_ip6(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth and ipv6 items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_eth_ip6(const struct rte_flow_item pattern[],\n+\t\t\t   struct rte_flow *flow,\n+\t\t\t   struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_eth_ip4_ip6(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth, ip4 and tcp/udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param tcp 1 to parse tcp item, 0 to parse udp item.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_eth_ip4_tcp_udp(const struct rte_flow_item pattern[],\n+\t\t\t\t   struct rte_flow *flow,\n+\t\t\t\t   struct rte_flow_error *error, int tcp)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = mrvl_parse_pattern_eth_ip4_ip6(pattern, flow, error, 0);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\titem = mrvl_next_item(item + 1);\n+\n+\tif (tcp)\n+\t\treturn mrvl_parse_tcp(item, flow, error);\n+\n+\treturn mrvl_parse_udp(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth, ipv4 and tcp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_eth_ip4_tcp(const struct rte_flow_item pattern[],\n+\t\t\t       struct rte_flow *flow,\n+\t\t\t       struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_eth_ip4_tcp_udp(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth, ipv4 and udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_eth_ip4_udp(const struct rte_flow_item pattern[],\n+\t\t\t       struct rte_flow *flow,\n+\t\t\t       struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_eth_ip4_tcp_udp(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth, ipv6 and tcp/udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param tcp 1 to parse tcp item, 0 to parse udp item.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_eth_ip6_tcp_udp(const struct rte_flow_item pattern[],\n+\t\t\t\t   struct rte_flow *flow,\n+\t\t\t\t   struct rte_flow_error *error, int tcp)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = mrvl_parse_pattern_eth_ip4_ip6(pattern, flow, error, 1);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\titem = mrvl_next_item(item + 1);\n+\n+\tif (tcp)\n+\t\treturn mrvl_parse_tcp(item, flow, error);\n+\n+\treturn mrvl_parse_udp(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth, ipv6 and tcp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_eth_ip6_tcp(const struct rte_flow_item pattern[],\n+\t\t\t       struct rte_flow *flow,\n+\t\t\t       struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_eth_ip6_tcp_udp(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the eth, ipv6 and udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_eth_ip6_udp(const struct rte_flow_item pattern[],\n+\t\t\t       struct rte_flow *flow,\n+\t\t\t       struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_eth_ip6_tcp_udp(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan item.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_vlan(const struct rte_flow_item pattern[],\n+\t\t\t    struct rte_flow *flow,\n+\t\t\t    struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\n+\treturn mrvl_parse_vlan(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan and ip4/ip6 items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param ip6 1 to parse ip6 item, 0 to parse ip4 item.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_vlan_ip4_ip6(const struct rte_flow_item pattern[],\n+\t\t\t\tstruct rte_flow *flow,\n+\t\t\t\tstruct rte_flow_error *error, int ip6)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = mrvl_parse_vlan(item, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\n+\treturn ip6 ? mrvl_parse_ip6(item, flow, error) :\n+\t\t     mrvl_parse_ip4(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan and ipv4 items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_vlan_ip4(const struct rte_flow_item pattern[],\n+\t\t\t    struct rte_flow *flow,\n+\t\t\t    struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_vlan_ip4_ip6(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan, ipv4 and tcp/udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_vlan_ip_tcp_udp(const struct rte_flow_item pattern[],\n+\t\t\t\t   struct rte_flow *flow,\n+\t\t\t\t   struct rte_flow_error *error, int tcp)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = mrvl_parse_pattern_vlan_ip4_ip6(pattern, flow, error, 0);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\titem = mrvl_next_item(item + 1);\n+\n+\tif (tcp)\n+\t\treturn mrvl_parse_tcp(item, flow, error);\n+\n+\treturn mrvl_parse_udp(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan, ipv4 and tcp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_vlan_ip_tcp(const struct rte_flow_item pattern[],\n+\t\t\t       struct rte_flow *flow,\n+\t\t\t       struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_vlan_ip_tcp_udp(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan, ipv4 and udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_vlan_ip_udp(const struct rte_flow_item pattern[],\n+\t\t\t       struct rte_flow *flow,\n+\t\t\t       struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_vlan_ip_tcp_udp(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan and ipv6 items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_vlan_ip6(const struct rte_flow_item pattern[],\n+\t\t\t    struct rte_flow *flow,\n+\t\t\t    struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_vlan_ip4_ip6(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan, ipv6 and tcp/udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_vlan_ip6_tcp_udp(const struct rte_flow_item pattern[],\n+\t\t\t\t    struct rte_flow *flow,\n+\t\t\t\t    struct rte_flow_error *error, int tcp)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = mrvl_parse_pattern_vlan_ip4_ip6(pattern, flow, error, 1);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\titem = mrvl_next_item(item + 1);\n+\n+\tif (tcp)\n+\t\treturn mrvl_parse_tcp(item, flow, error);\n+\n+\treturn mrvl_parse_udp(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan, ipv6 and tcp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_vlan_ip6_tcp(const struct rte_flow_item pattern[],\n+\t\t\t\tstruct rte_flow *flow,\n+\t\t\t\tstruct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_vlan_ip6_tcp_udp(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the vlan, ipv6 and udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_vlan_ip6_udp(const struct rte_flow_item pattern[],\n+\t\t\t\tstruct rte_flow *flow,\n+\t\t\t\tstruct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_vlan_ip6_tcp_udp(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the ip4/ip6 item.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param ip6 1 to parse ip6 item, 0 to parse ip4 item.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_ip4_ip6(const struct rte_flow_item pattern[],\n+\t\t       struct rte_flow *flow,\n+\t\t       struct rte_flow_error *error, int ip6)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\n+\treturn ip6 ? mrvl_parse_ip6(item, flow, error) :\n+\t\t     mrvl_parse_ip4(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the ipv4 item.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_ip4(const struct rte_flow_item pattern[],\n+\t\t       struct rte_flow *flow,\n+\t\t       struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_ip4_ip6(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the ipv6 item.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_ip6(const struct rte_flow_item pattern[],\n+\t\t       struct rte_flow *flow,\n+\t\t       struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_ip4_ip6(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the ip4/ip6 and tcp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @param ip6 1 to parse ip6 item, 0 to parse ip4 item.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_ip4_ip6_tcp(const struct rte_flow_item pattern[],\n+\t\t\t   struct rte_flow *flow,\n+\t\t\t   struct rte_flow_error *error, int ip6)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = ip6 ? mrvl_parse_ip6(item, flow, error) :\n+\t\t    mrvl_parse_ip4(item, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\n+\treturn mrvl_parse_tcp(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the ipv4 and tcp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_ip4_tcp(const struct rte_flow_item pattern[],\n+\t\t\t   struct rte_flow *flow,\n+\t\t\t   struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_ip4_ip6_tcp(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the ipv6 and tcp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_ip6_tcp(const struct rte_flow_item pattern[],\n+\t\t\t   struct rte_flow *flow,\n+\t\t\t   struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_ip4_ip6_tcp(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the ipv4/ipv6 and udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_ip4_ip6_udp(const struct rte_flow_item pattern[],\n+\t\t\t   struct rte_flow *flow,\n+\t\t\t   struct rte_flow_error *error, int ip6)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\tint ret;\n+\n+\tret = ip6 ? mrvl_parse_ip6(item, flow, error) :\n+\t\t    mrvl_parse_ip4(item, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem = mrvl_next_item(item + 1);\n+\n+\treturn mrvl_parse_udp(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the ipv4 and udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_ip4_udp(const struct rte_flow_item pattern[],\n+\t\t\t   struct rte_flow *flow,\n+\t\t\t   struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_ip4_ip6_udp(pattern, flow, error, 0);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the ipv6 and udp items.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static inline int\n+mrvl_parse_pattern_ip6_udp(const struct rte_flow_item pattern[],\n+\t\t\t   struct rte_flow *flow,\n+\t\t\t   struct rte_flow_error *error)\n+{\n+\treturn mrvl_parse_pattern_ip4_ip6_udp(pattern, flow, error, 1);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the tcp item.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_tcp(const struct rte_flow_item pattern[],\n+\t\t       struct rte_flow *flow,\n+\t\t       struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\n+\treturn mrvl_parse_tcp(item, flow, error);\n+}\n+\n+/**\n+ * Parse flow pattern composed of the udp item.\n+ *\n+ * @param pattern Pointer to the flow pattern table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_parse_pattern_udp(const struct rte_flow_item pattern[],\n+\t\t       struct rte_flow *flow,\n+\t\t       struct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_item *item = mrvl_next_item(pattern);\n+\n+\treturn mrvl_parse_udp(item, flow, error);\n+}\n+\n+/**\n+ * Structure used to map specific flow pattern to the pattern parse callback\n+ * which will iterate over each pattern item and extract relevant data.\n+ */\n+static const struct {\n+\tconst enum rte_flow_item_type *pattern;\n+\tint (*parse)(const struct rte_flow_item pattern[],\n+\t\tstruct rte_flow *flow,\n+\t\tstruct rte_flow_error *error);\n+} mrvl_patterns[] = {\n+\t{ pattern_eth, mrvl_parse_pattern_eth },\n+\t{ pattern_eth_vlan, mrvl_parse_pattern_eth_vlan },\n+\t{ pattern_eth_vlan_ip, mrvl_parse_pattern_eth_vlan_ip4 },\n+\t{ pattern_eth_vlan_ip6, mrvl_parse_pattern_eth_vlan_ip6 },\n+\t{ pattern_eth_ip4, mrvl_parse_pattern_eth_ip4 },\n+\t{ pattern_eth_ip4_tcp, mrvl_parse_pattern_eth_ip4_tcp },\n+\t{ pattern_eth_ip4_udp, mrvl_parse_pattern_eth_ip4_udp },\n+\t{ pattern_eth_ip6, mrvl_parse_pattern_eth_ip6 },\n+\t{ pattern_eth_ip6_tcp, mrvl_parse_pattern_eth_ip6_tcp },\n+\t{ pattern_eth_ip6_udp, mrvl_parse_pattern_eth_ip6_udp },\n+\t{ pattern_vlan, mrvl_parse_pattern_vlan },\n+\t{ pattern_vlan_ip, mrvl_parse_pattern_vlan_ip4 },\n+\t{ pattern_vlan_ip_tcp, mrvl_parse_pattern_vlan_ip_tcp },\n+\t{ pattern_vlan_ip_udp, mrvl_parse_pattern_vlan_ip_udp },\n+\t{ pattern_vlan_ip6, mrvl_parse_pattern_vlan_ip6 },\n+\t{ pattern_vlan_ip6_tcp, mrvl_parse_pattern_vlan_ip6_tcp },\n+\t{ pattern_vlan_ip6_udp, mrvl_parse_pattern_vlan_ip6_udp },\n+\t{ pattern_ip, mrvl_parse_pattern_ip4 },\n+\t{ pattern_ip_tcp, mrvl_parse_pattern_ip4_tcp },\n+\t{ pattern_ip_udp, mrvl_parse_pattern_ip4_udp },\n+\t{ pattern_ip6, mrvl_parse_pattern_ip6 },\n+\t{ pattern_ip6_tcp, mrvl_parse_pattern_ip6_tcp },\n+\t{ pattern_ip6_udp, mrvl_parse_pattern_ip6_udp },\n+\t{ pattern_tcp, mrvl_parse_pattern_tcp },\n+\t{ pattern_udp, mrvl_parse_pattern_udp }\n+};\n+\n+/**\n+ * Check whether provided pattern matches any of the supported ones.\n+ *\n+ * @param type_pattern Pointer to the pattern type.\n+ * @param item_pattern Pointer to the flow pattern.\n+ * @returns 1 in case of success, 0 value otherwise.\n+ */\n+static int\n+mrvl_patterns_match(const enum rte_flow_item_type *type_pattern,\n+\t\t    const struct rte_flow_item *item_pattern)\n+{\n+\tconst enum rte_flow_item_type *type = type_pattern;\n+\tconst struct rte_flow_item *item = item_pattern;\n+\n+\tfor (;;) {\n+\t\tif (item->type == RTE_FLOW_ITEM_TYPE_VOID) {\n+\t\t\titem++;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (*type == RTE_FLOW_ITEM_TYPE_END ||\n+\t\t    item->type == RTE_FLOW_ITEM_TYPE_END)\n+\t\t\tbreak;\n+\n+\t\tif (*type != item->type)\n+\t\t\tbreak;\n+\n+\t\titem++;\n+\t\ttype++;\n+\t}\n+\n+\treturn *type == item->type;\n+}\n+\n+/**\n+ * Parse flow attribute.\n+ *\n+ * This will check whether the provided attribute's flags are supported.\n+ *\n+ * @param priv Unused\n+ * @param attr Pointer to the flow attribute.\n+ * @param flow Unused\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_flow_parse_attr(struct mrvl_priv *priv __rte_unused,\n+\t\t     const struct rte_flow_attr *attr,\n+\t\t     struct rte_flow *flow __rte_unused,\n+\t\t     struct rte_flow_error *error)\n+{\n+\tif (!attr) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR,\n+\t\t\t\t   NULL, \"NULL attribute\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (attr->group) {\n+\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR_GROUP, NULL,\n+\t\t\t\t   \"Groups are not supported\");\n+\t\treturn -rte_errno;\n+\t}\n+\tif (attr->priority) {\n+\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, NULL,\n+\t\t\t\t   \"Priorities are not supported\");\n+\t\treturn -rte_errno;\n+\t}\n+\tif (!attr->ingress) {\n+\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, NULL,\n+\t\t\t\t   \"Only ingress is supported\");\n+\t\treturn -rte_errno;\n+\t}\n+\tif (attr->egress) {\n+\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, NULL,\n+\t\t\t\t   \"Egress is not supported\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse flow pattern.\n+ *\n+ * Specific classifier rule will be created as well.\n+ *\n+ * @param priv Unused\n+ * @param pattern Pointer to the flow pattern.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_flow_parse_pattern(struct mrvl_priv *priv __rte_unused,\n+\t\t\tconst struct rte_flow_item pattern[],\n+\t\t\tstruct rte_flow *flow,\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tunsigned int i;\n+\tint ret;\n+\n+\tfor (i = 0; i < RTE_DIM(mrvl_patterns); i++) {\n+\t\tif (!mrvl_patterns_match(mrvl_patterns[i].pattern, pattern))\n+\t\t\tcontinue;\n+\n+\t\tret = mrvl_patterns[i].parse(pattern, flow, error);\n+\t\tif (ret)\n+\t\t\tmrvl_free_all_key_mask(&flow->rule);\n+\n+\t\treturn ret;\n+\t}\n+\n+\trte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, NULL,\n+\t\t\t   \"Unsupported pattern\");\n+\n+\treturn -rte_errno;\n+}\n+\n+/**\n+ * Parse flow actions.\n+ *\n+ * @param priv Pointer to the port's private data.\n+ * @param actions Pointer the action table.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_flow_parse_actions(struct mrvl_priv *priv,\n+\t\t\tconst struct rte_flow_action actions[],\n+\t\t\tstruct rte_flow *flow,\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct rte_flow_action *action = actions;\n+\tint specified = 0;\n+\n+\tfor (; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {\n+\t\tif (action->type == RTE_FLOW_ACTION_TYPE_VOID)\n+\t\t\tcontinue;\n+\n+\t\tif (action->type == RTE_FLOW_ACTION_TYPE_DROP) {\n+\t\t\tflow->cos.ppio = priv->ppio;\n+\t\t\tflow->cos.tc = 0;\n+\t\t\tflow->action.type = PP2_CLS_TBL_ACT_DROP;\n+\t\t\tflow->action.cos = &flow->cos;\n+\t\t\tspecified++;\n+\t\t} else if (action->type == RTE_FLOW_ACTION_TYPE_QUEUE) {\n+\t\t\tconst struct rte_flow_action_queue *q =\n+\t\t\t\t(const struct rte_flow_action_queue *)\n+\t\t\t\taction->conf;\n+\n+\t\t\tif (q->index > priv->nb_rx_queues) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\tNULL,\n+\t\t\t\t\t\t\"Queue index out of range\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tif (priv->rxq_map[q->index].tc == MRVL_UNKNOWN_TC) {\n+\t\t\t\t/*\n+\t\t\t\t * Unknown TC mapping, mapping will not have\n+\t\t\t\t * a correct queue.\n+\t\t\t\t */\n+\t\t\t\tRTE_LOG(ERR, PMD,\n+\t\t\t\t\t\"Unknown TC mapping for queue %hu eth%hhu\\n\",\n+\t\t\t\t\tq->index, priv->ppio_id);\n+\n+\t\t\t\trte_flow_error_set(error, EFAULT,\n+\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t\tNULL, NULL);\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tRTE_LOG(DEBUG, PMD,\n+\t\t\t\t\"Action: Assign packets to queue %d, tc:%d, q:%d\\n\",\n+\t\t\t\tq->index, priv->rxq_map[q->index].tc,\n+\t\t\t\tpriv->rxq_map[q->index].inq);\n+\n+\t\t\tflow->cos.ppio = priv->ppio;\n+\t\t\tflow->cos.tc = priv->rxq_map[q->index].tc;\n+\t\t\tflow->action.type = PP2_CLS_TBL_ACT_DONE;\n+\t\t\tflow->action.cos = &flow->cos;\n+\t\t\tspecified++;\n+\t\t} else {\n+\t\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ACTION, NULL,\n+\t\t\t\t\t   \"Action not supported\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n+\t}\n+\n+\tif (!specified) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t   NULL, \"Action not specified\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse flow attribute, pattern and actions.\n+ *\n+ * @param priv Pointer to the port's private data.\n+ * @param attr Pointer to the flow attribute.\n+ * @param pattern Pointer to the flow pattern.\n+ * @param actions Pointer to the flow actions.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 on success, negative value otherwise.\n+ */\n+static int\n+mrvl_flow_parse(struct mrvl_priv *priv, const 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 *flow,\n+\t\tstruct rte_flow_error *error)\n+{\n+\tint ret;\n+\n+\tret = mrvl_flow_parse_attr(priv, attr, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = mrvl_flow_parse_pattern(priv, pattern, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn mrvl_flow_parse_actions(priv, actions, flow, error);\n+}\n+\n+static inline enum pp2_cls_tbl_type\n+mrvl_engine_type(const struct rte_flow *flow)\n+{\n+\tint i, size = 0;\n+\n+\tfor (i = 0; i < flow->rule.num_fields; i++)\n+\t\tsize += flow->rule.fields[i].size;\n+\n+\t/*\n+\t * For maskable engine type the key size must be up to 8 bytes.\n+\t * For keys with size bigger than 8 bytes, engine type must\n+\t * be set to exact match.\n+\t */\n+\tif (size > 8)\n+\t\treturn PP2_CLS_TBL_EXACT_MATCH;\n+\n+\treturn PP2_CLS_TBL_MASKABLE;\n+}\n+\n+static int\n+mrvl_create_cls_table(struct rte_eth_dev *dev, struct rte_flow *first_flow)\n+{\n+\tstruct mrvl_priv *priv = dev->data->dev_private;\n+\tstruct pp2_cls_tbl_key *key = &priv->cls_tbl_params.key;\n+\tint ret;\n+\n+\tif (priv->cls_tbl) {\n+\t\tpp2_cls_tbl_deinit(priv->cls_tbl);\n+\t\tpriv->cls_tbl = NULL;\n+\t}\n+\n+\tmemset(&priv->cls_tbl_params, 0, sizeof(priv->cls_tbl_params));\n+\n+\tpriv->cls_tbl_params.type = mrvl_engine_type(first_flow);\n+\tRTE_LOG(INFO, PMD, \"Setting cls search engine type to %s\\n\",\n+\t\t\tpriv->cls_tbl_params.type == PP2_CLS_TBL_EXACT_MATCH ?\n+\t\t\t\"exact\" : \"maskable\");\n+\tpriv->cls_tbl_params.max_num_rules = MRVL_CLS_MAX_NUM_RULES;\n+\tpriv->cls_tbl_params.default_act.type = PP2_CLS_TBL_ACT_DONE;\n+\tpriv->cls_tbl_params.default_act.cos = &first_flow->cos;\n+\n+\tif (first_flow->pattern & F_DMAC) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_ETH;\n+\t\tkey->proto_field[key->num_fields].field.eth = MV_NET_ETH_F_DA;\n+\t\tkey->key_size += 6;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_SMAC) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_ETH;\n+\t\tkey->proto_field[key->num_fields].field.eth = MV_NET_ETH_F_SA;\n+\t\tkey->key_size += 6;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_TYPE) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_ETH;\n+\t\tkey->proto_field[key->num_fields].field.eth = MV_NET_ETH_F_TYPE;\n+\t\tkey->key_size += 2;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_VLAN_ID) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_VLAN;\n+\t\tkey->proto_field[key->num_fields].field.vlan = MV_NET_VLAN_F_ID;\n+\t\tkey->key_size += 2;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_VLAN_PRI) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_VLAN;\n+\t\tkey->proto_field[key->num_fields].field.vlan =\n+\t\t\tMV_NET_VLAN_F_PRI;\n+\t\tkey->key_size += 1;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_IP4_TOS) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_IP4;\n+\t\tkey->proto_field[key->num_fields].field.ipv4 = MV_NET_IP4_F_TOS;\n+\t\tkey->key_size += 1;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_IP4_SIP) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_IP4;\n+\t\tkey->proto_field[key->num_fields].field.ipv4 = MV_NET_IP4_F_SA;\n+\t\tkey->key_size += 4;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_IP4_DIP) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_IP4;\n+\t\tkey->proto_field[key->num_fields].field.ipv4 = MV_NET_IP4_F_DA;\n+\t\tkey->key_size += 4;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_IP4_PROTO) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_IP4;\n+\t\tkey->proto_field[key->num_fields].field.ipv4 =\n+\t\t\tMV_NET_IP4_F_PROTO;\n+\t\tkey->key_size += 1;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_IP6_SIP) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_IP6;\n+\t\tkey->proto_field[key->num_fields].field.ipv6 = MV_NET_IP6_F_SA;\n+\t\tkey->key_size += 16;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_IP6_DIP) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_IP6;\n+\t\tkey->proto_field[key->num_fields].field.ipv6 = MV_NET_IP6_F_DA;\n+\t\tkey->key_size += 16;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_IP6_FLOW) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_IP6;\n+\t\tkey->proto_field[key->num_fields].field.ipv6 =\n+\t\t\tMV_NET_IP6_F_FLOW;\n+\t\tkey->key_size += 3;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_IP6_NEXT_HDR) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_IP6;\n+\t\tkey->proto_field[key->num_fields].field.ipv6 =\n+\t\t\tMV_NET_IP6_F_NEXT_HDR;\n+\t\tkey->key_size += 1;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_TCP_SPORT) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_TCP;\n+\t\tkey->proto_field[key->num_fields].field.tcp = MV_NET_TCP_F_SP;\n+\t\tkey->key_size += 2;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_TCP_DPORT) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_TCP;\n+\t\tkey->proto_field[key->num_fields].field.tcp = MV_NET_TCP_F_DP;\n+\t\tkey->key_size += 2;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_UDP_SPORT) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_UDP;\n+\t\tkey->proto_field[key->num_fields].field.tcp = MV_NET_TCP_F_SP;\n+\t\tkey->key_size += 2;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tif (first_flow->pattern & F_UDP_DPORT) {\n+\t\tkey->proto_field[key->num_fields].proto = MV_NET_PROTO_UDP;\n+\t\tkey->proto_field[key->num_fields].field.udp = MV_NET_TCP_F_DP;\n+\t\tkey->key_size += 2;\n+\t\tkey->num_fields += 1;\n+\t}\n+\n+\tret = pp2_cls_tbl_init(&priv->cls_tbl_params, &priv->cls_tbl);\n+\tif (!ret)\n+\t\tpriv->cls_tbl_pattern = first_flow->pattern;\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * Check whether new flow can be added to the table\n+ *\n+ * @param priv Pointer to the port's private data.\n+ * @param flow Pointer to the new flow.\n+ * @return 1 in case flow can be added, 0 otherwise.\n+ */\n+static inline int\n+mrvl_flow_can_be_added(struct mrvl_priv *priv, const struct rte_flow *flow)\n+{\n+\treturn flow->pattern == priv->cls_tbl_pattern &&\n+\t       mrvl_engine_type(flow) == priv->cls_tbl_params.type;\n+}\n+\n+/**\n+ * DPDK flow create callback called when flow is to be created.\n+ *\n+ * @param dev Pointer to the device.\n+ * @param attr Pointer to the flow attribute.\n+ * @param pattern Pointer to the flow pattern.\n+ * @param actions Pointer to the flow actions.\n+ * @param error Pointer to the flow error.\n+ * @returns Pointer to the created flow in case of success, NULL otherwise.\n+ */\n+static struct rte_flow *\n+mrvl_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 mrvl_priv *priv = dev->data->dev_private;\n+\tstruct rte_flow *flow, *first;\n+\tint ret;\n+\n+\tif (!dev->data->dev_started) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"Port must be started first\\n\");\n+\t\treturn NULL;\n+\t}\n+\n+\tflow = rte_zmalloc_socket(NULL, sizeof(*flow), 0, rte_socket_id());\n+\tif (!flow)\n+\t\treturn NULL;\n+\n+\tret = mrvl_flow_parse(priv, attr, pattern, actions, flow, error);\n+\tif (ret)\n+\t\tgoto out;\n+\n+\t/*\n+\t * Four cases here:\n+\t *\n+\t * 1. In case table does not exist - create one.\n+\t * 2. In case table exists, is empty and new flow cannot be added\n+\t *    recreate table.\n+\t * 3. In case table is not empty and new flow matches table format\n+\t *    add it.\n+\t * 4. Otherwise flow cannot be added.\n+\t */\n+\tfirst = LIST_FIRST(&priv->flows);\n+\tif (!priv->cls_tbl) {\n+\t\tret = mrvl_create_cls_table(dev, flow);\n+\t} else if (!first && !mrvl_flow_can_be_added(priv, flow)) {\n+\t\tret = mrvl_create_cls_table(dev, flow);\n+\t} else if (mrvl_flow_can_be_added(priv, flow)) {\n+\t\tret = 0;\n+\t} else {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"Pattern does not match cls table format\\n\");\n+\t\tgoto out;\n+\t}\n+\n+\tif (ret) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"Failed to create cls table\\n\");\n+\t\tgoto out;\n+\t}\n+\n+\tret = pp2_cls_tbl_add_rule(priv->cls_tbl, &flow->rule, &flow->action);\n+\tif (ret) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"Failed to add rule\\n\");\n+\t\tgoto out;\n+\t}\n+\n+\tLIST_INSERT_HEAD(&priv->flows, flow, next);\n+\n+\treturn flow;\n+out:\n+\trte_free(flow);\n+\treturn NULL;\n+}\n+\n+/**\n+ * Remove classifier rule associated with given flow.\n+ *\n+ * @param priv Pointer to the port's private data.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_flow_remove(struct mrvl_priv *priv, struct rte_flow *flow,\n+\t\t struct rte_flow_error *error)\n+{\n+\tint ret;\n+\n+\tif (!priv->cls_tbl) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"Classifier table not initialized\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tret = pp2_cls_tbl_remove_rule(priv->cls_tbl, &flow->rule);\n+\tif (ret) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"Failed to remove rule\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tmrvl_free_all_key_mask(&flow->rule);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * DPDK flow destroy callback called when flow is to be removed.\n+ *\n+ * @param priv Pointer to the port's private data.\n+ * @param flow Pointer to the flow.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,\n+\t\t  struct rte_flow_error *error)\n+{\n+\tstruct mrvl_priv *priv = dev->data->dev_private;\n+\tstruct rte_flow *f;\n+\tint ret;\n+\n+\tLIST_FOREACH(f, &priv->flows, next) {\n+\t\tif (f == flow)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (!flow) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"Rule was not found\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tLIST_REMOVE(f, next);\n+\n+\tret = mrvl_flow_remove(priv, flow, error);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\trte_free(flow);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * DPDK flow callback called to verify given attribute, pattern and actions.\n+ *\n+ * @param dev Pointer to the device.\n+ * @param attr Pointer to the flow attribute.\n+ * @param pattern Pointer to the flow pattern.\n+ * @param actions Pointer to the flow actions.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 on success, negative value otherwise.\n+ */\n+static int\n+mrvl_flow_validate(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+\tstatic struct rte_flow *flow;\n+\n+\tflow = mrvl_flow_create(dev, attr, pattern, actions, error);\n+\tif (!flow)\n+\t\treturn -rte_errno;\n+\n+\tmrvl_flow_destroy(dev, flow, error);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * DPDK flow flush callback called when flows are to be flushed.\n+ *\n+ * @param dev Pointer to the device.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)\n+{\n+\tstruct mrvl_priv *priv = dev->data->dev_private;\n+\n+\twhile (!LIST_EMPTY(&priv->flows)) {\n+\t\tstruct rte_flow *flow = LIST_FIRST(&priv->flows);\n+\t\tint ret = mrvl_flow_remove(priv, flow, error);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tLIST_REMOVE(flow, next);\n+\t\trte_free(flow);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * DPDK flow isolate callback called to isolate port.\n+ *\n+ * @param dev Pointer to the device.\n+ * @param enable Pass 0/1 to disable/enable port isolation.\n+ * @param error Pointer to the flow error.\n+ * @returns 0 in case of success, negative value otherwise.\n+ */\n+static int\n+mrvl_flow_isolate(struct rte_eth_dev *dev, int enable,\n+\t\t  struct rte_flow_error *error)\n+{\n+\tstruct mrvl_priv *priv = dev->data->dev_private;\n+\n+\tif (dev->data->dev_started) {\n+\t\trte_flow_error_set(error, EBUSY,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t   NULL, \"Port must be stopped first\\n\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tpriv->isolated = enable;\n+\n+\treturn 0;\n+}\n+\n+const struct rte_flow_ops mrvl_flow_ops = {\n+\t.validate = mrvl_flow_validate,\n+\t.create = mrvl_flow_create,\n+\t.destroy = mrvl_flow_destroy,\n+\t.flush = mrvl_flow_flush,\n+\t.isolate = mrvl_flow_isolate\n+};\n",
    "prefixes": [
        "dpdk-dev",
        "5/8"
    ]
}