get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 27385,
    "url": "http://patches.dpdk.org/api/patches/27385/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/c5bd7b701835175bd07363dfe745385abcf906e1.1501681927.git.nelio.laranjeiro@6wind.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": "<c5bd7b701835175bd07363dfe745385abcf906e1.1501681927.git.nelio.laranjeiro@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/c5bd7b701835175bd07363dfe745385abcf906e1.1501681927.git.nelio.laranjeiro@6wind.com",
    "date": "2017-08-02T14:10:34",
    "name": "[dpdk-dev,v1,18/21] net/mlx5: use flow to enable unicast traffic",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "3d3c88cff7ca29d80521e8a27b5b9ba742239b59",
    "submitter": {
        "id": 243,
        "url": "http://patches.dpdk.org/api/people/243/?format=api",
        "name": "Nélio Laranjeiro",
        "email": "nelio.laranjeiro@6wind.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/c5bd7b701835175bd07363dfe745385abcf906e1.1501681927.git.nelio.laranjeiro@6wind.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/27385/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/27385/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 [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 36935A246;\n\tWed,  2 Aug 2017 16:11:44 +0200 (CEST)",
            "from mail-wm0-f44.google.com (mail-wm0-f44.google.com\n\t[74.125.82.44]) by dpdk.org (Postfix) with ESMTP id B24DDA0D4\n\tfor <dev@dpdk.org>; Wed,  2 Aug 2017 16:11:16 +0200 (CEST)",
            "by mail-wm0-f44.google.com with SMTP id m85so42757840wma.1\n\tfor <dev@dpdk.org>; Wed, 02 Aug 2017 07:11:16 -0700 (PDT)",
            "from ping.dev.6wind.com (host.78.145.23.62.rev.coltfrance.com.\n\t[62.23.145.78]) by smtp.gmail.com with ESMTPSA id\n\td53sm39449552wrd.81.2017.08.02.07.11.12\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tWed, 02 Aug 2017 07:11:12 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:in-reply-to:references;\n\tbh=t+SYFWEEt2EhFN4DxSMpQQ27f+aGf30X6guzCha/JwY=;\n\tb=KbUqtBNQRYiJ51rm4lQY4h3YG7D95YGAEPioBQQzk2yizg4y/I1uTtYtHncp+oYLLv\n\t53uDl6xCte2xUNsgJk9r3QF1djXGV14I1kAiWZ+PhUEZp2U0G2n/jTK9ySVUrlxQU9Ja\n\tOBW8eGYOhi8rZn8U/DJDYpyH2PMHTRXQMoLKZ/5dXGboJDs6qf1zQrsXdoFX4gpgwxTA\n\tYnjG4Ee3wQyg7A1Z/t6X9yHOPLN66Ev0pk0QAvC/COkb9ZESVb8/pBujEh78T1EGLStO\n\tEwzySqQX4i371evB55zoUFhczTa+S2c9I1LKBJkXYD/naIWm/s0lY5tTryXb4gQ3Ucbo\n\tuH3w==",
        "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:in-reply-to:references;\n\tbh=t+SYFWEEt2EhFN4DxSMpQQ27f+aGf30X6guzCha/JwY=;\n\tb=eXGOjB1hflUCbdcGdOrAYGpH8wrIX0SxZeihGHng2rUBRjfSQf8EYIxNLXsWplwwYZ\n\t20JRRp40sM9dZ21cx1iKlii2ZHHIXOBJY/7V5V6Vgikf59YjBjdCj1xp5abD74pQ/NsI\n\tNMPKNSj01h2CUVnqKJMxvxNW93io37zkb4sPsTFq2JMFyMYXz8nj071XY3uB/UqQmUnK\n\teY2IY0Z+6s1SyNbIuEK2yxz9VyjuqXERVYX12XSoDj/uu2cODi6vR/V/sX7hoyfw9vr+\n\tHQcZVOp1NFIc8Ghyi5QqLMDZYJozbDZR5GF2fxCajO6w2pdXF3Hr0WMU9Wxv//fcLVy+\n\tVoRQ==",
        "X-Gm-Message-State": "AIVw110796vbREA58ajCRAvmLzvul3fFFk2WEbYbnk8Sj57MIwiphckW\n\tcqyQIhijr5j28KoZBfS5WQ==",
        "X-Received": "by 10.28.142.203 with SMTP id q194mr4095477wmd.174.1501683074967;\n\tWed, 02 Aug 2017 07:11:14 -0700 (PDT)",
        "From": "Nelio Laranjeiro <nelio.laranjeiro@6wind.com>",
        "To": "dev@dpdk.org",
        "Cc": "adrien.mazarguil@6wind.com",
        "Date": "Wed,  2 Aug 2017 16:10:34 +0200",
        "Message-Id": "<c5bd7b701835175bd07363dfe745385abcf906e1.1501681927.git.nelio.laranjeiro@6wind.com>",
        "X-Mailer": "git-send-email 2.1.4",
        "In-Reply-To": [
            "<cover.1501681927.git.nelio.laranjeiro@6wind.com>",
            "<cover.1501681927.git.nelio.laranjeiro@6wind.com>"
        ],
        "References": [
            "<cover.1501681927.git.nelio.laranjeiro@6wind.com>",
            "<cover.1501681927.git.nelio.laranjeiro@6wind.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH v1 18/21] net/mlx5: use flow to enable unicast\n\ttraffic",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "RSS hash configuration is currently ignored by the PMD, this commits\nremoves the RSS feature.\n\nThis functionality will be added in a later commit.\n\nSigned-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>\n---\n drivers/net/mlx5/mlx5.c         |   9 +-\n drivers/net/mlx5/mlx5.h         |  22 +--\n drivers/net/mlx5/mlx5_defs.h    |   3 -\n drivers/net/mlx5/mlx5_flow.c    |  26 ++-\n drivers/net/mlx5/mlx5_mac.c     | 403 +++-------------------------------------\n drivers/net/mlx5/mlx5_rxmode.c  | 332 +--------------------------------\n drivers/net/mlx5/mlx5_rxq.c     |  65 -------\n drivers/net/mlx5/mlx5_rxtx.h    |  26 ---\n drivers/net/mlx5/mlx5_trigger.c | 181 ++++++++++++++++--\n drivers/net/mlx5/mlx5_vlan.c    |  54 ++----\n 10 files changed, 231 insertions(+), 890 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex f000404..af3f7c8 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -146,13 +146,12 @@ mlx5_dev_close(struct rte_eth_dev *dev)\n \t      ((priv->ctx != NULL) ? priv->ctx->device->name : \"\"));\n \t/* In case mlx5_dev_stop() has not been called. */\n \tpriv_dev_interrupt_handler_uninstall(priv, dev);\n-\tpriv_special_flow_disable_all(priv);\n-\tpriv_mac_addrs_disable(priv);\n \tpriv_destroy_hash_rxqs(priv);\n \n \t/* Prevent crashes when queues are still in use. */\n \tdev->rx_pkt_burst = removed_rx_burst;\n \tdev->tx_pkt_burst = removed_tx_burst;\n+\tpriv_dev_traffic_disable(priv, dev);\n \tif (priv->rxqs != NULL) {\n \t\t/* XXX race condition if mlx5_rx_burst() is still running. */\n \t\tusleep(1000);\n@@ -734,10 +733,6 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)\n \t\t     mac.addr_bytes[0], mac.addr_bytes[1],\n \t\t     mac.addr_bytes[2], mac.addr_bytes[3],\n \t\t     mac.addr_bytes[4], mac.addr_bytes[5]);\n-\t\t/* Register MAC address. */\n-\t\tclaim_zero(priv_mac_addr_add(priv, 0,\n-\t\t\t\t\t     (const uint8_t (*)[ETHER_ADDR_LEN])\n-\t\t\t\t\t     mac.addr_bytes));\n #ifndef NDEBUG\n \t\t{\n \t\t\tchar ifname[IF_NAMESIZE];\n@@ -774,6 +769,8 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)\n \t\teth_dev->device->driver = &mlx5_driver.driver;\n \t\tpriv->dev = eth_dev;\n \t\teth_dev->dev_ops = &mlx5_dev_ops;\n+\t\t/* Register MAC address. */\n+\t\tclaim_zero(mlx5_mac_addr_add(eth_dev, &mac, 0, 0));\n \t\tTAILQ_INIT(&priv->flows);\n \t\tTAILQ_INIT(&priv->ctrl_flows);\n \ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex ba461a3..ee0de3c 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -95,13 +95,7 @@ struct priv {\n \tstruct ibv_context *ctx; /* Verbs context. */\n \tstruct ibv_device_attr device_attr; /* Device properties. */\n \tstruct ibv_pd *pd; /* Protection Domain. */\n-\t/*\n-\t * MAC addresses array and configuration bit-field.\n-\t * An extra entry that cannot be modified by the DPDK is reserved\n-\t * for broadcast frames (destination MAC address ff:ff:ff:ff:ff:ff).\n-\t */\n-\tstruct ether_addr mac[MLX5_MAX_MAC_ADDRESSES];\n-\tBITFIELD_DECLARE(mac_configured, uint32_t, MLX5_MAX_MAC_ADDRESSES);\n+\tstruct ether_addr mac[MLX5_MAX_MAC_ADDRESSES]; /* MAC addresses. */\n \tuint16_t vlan_filter[MLX5_MAX_VLAN_IDS]; /* VLAN filters table. */\n \tunsigned int vlan_filter_n; /* Number of configured VLAN filters. */\n \t/* Device properties. */\n@@ -221,13 +215,7 @@ void priv_select_rx_function(struct priv *);\n /* mlx5_mac.c */\n \n int priv_get_mac(struct priv *, uint8_t (*)[ETHER_ADDR_LEN]);\n-void hash_rxq_mac_addrs_del(struct hash_rxq *);\n-void priv_mac_addrs_disable(struct priv *);\n void mlx5_mac_addr_remove(struct rte_eth_dev *, uint32_t);\n-int hash_rxq_mac_addrs_add(struct hash_rxq *);\n-int priv_mac_addr_add(struct priv *, unsigned int,\n-\t\t      const uint8_t (*)[ETHER_ADDR_LEN]);\n-int priv_mac_addrs_enable(struct priv *);\n int mlx5_mac_addr_add(struct rte_eth_dev *, struct ether_addr *, uint32_t,\n \t\t      uint32_t);\n void mlx5_mac_addr_set(struct rte_eth_dev *, struct ether_addr *);\n@@ -246,10 +234,6 @@ int mlx5_dev_rss_reta_update(struct rte_eth_dev *,\n \n /* mlx5_rxmode.c */\n \n-int priv_special_flow_enable(struct priv *, enum hash_rxq_flow_type);\n-void priv_special_flow_disable(struct priv *, enum hash_rxq_flow_type);\n-int priv_special_flow_enable_all(struct priv *);\n-void priv_special_flow_disable_all(struct priv *);\n void mlx5_promiscuous_enable(struct rte_eth_dev *);\n void mlx5_promiscuous_disable(struct rte_eth_dev *);\n void mlx5_allmulticast_enable(struct rte_eth_dev *);\n@@ -276,6 +260,10 @@ void mlx5_vlan_strip_queue_set(struct rte_eth_dev *, uint16_t, int);\n \n int mlx5_dev_start(struct rte_eth_dev *);\n void mlx5_dev_stop(struct rte_eth_dev *);\n+int priv_dev_traffic_enable(struct priv *, struct rte_eth_dev *);\n+int priv_dev_traffic_disable(struct priv *, struct rte_eth_dev *);\n+int priv_dev_traffic_restart(struct priv *, struct rte_eth_dev *);\n+int mlx5_traffic_restart(struct rte_eth_dev *);\n \n /* mlx5_flow.c */\n \ndiff --git a/drivers/net/mlx5/mlx5_defs.h b/drivers/net/mlx5/mlx5_defs.h\nindex a76bc6f..969315c 100644\n--- a/drivers/net/mlx5/mlx5_defs.h\n+++ b/drivers/net/mlx5/mlx5_defs.h\n@@ -45,9 +45,6 @@\n /* Maximum number of simultaneous VLAN filters. */\n #define MLX5_MAX_VLAN_IDS 128\n \n-/* Maximum number of special flows. */\n-#define MLX5_MAX_SPECIAL_FLOWS 4\n-\n /*\n  * Request TX completion every time descriptors reach this threshold since\n  * the previous request. Must be a power of two for performance reasons.\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex 39a49af..8316255 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -1029,20 +1029,18 @@ priv_flow_create_action_queue(struct priv *priv,\n \t\t\t\t\t    flow->hash_fields,\n \t\t\t\t\t    flow->actions.queues,\n \t\t\t\t\t    flow->actions.queues_n);\n-\tif (rte_flow->hrxq) {\n-\t\trte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,\n-\t\t\t\t   NULL, \"duplicated flow\");\n-\t\tgoto error;\n-\t}\n-\trte_flow->hrxq = mlx5_priv_hrxq_new(priv, rss_hash_default_key,\n-\t\t\t\t\t    rss_hash_default_key_len,\n-\t\t\t\t\t    flow->hash_fields,\n-\t\t\t\t\t    flow->actions.queues,\n-\t\t\t\t\t    flow->actions.queues_n);\n \tif (!rte_flow->hrxq) {\n-\t\trte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,\n-\t\t\t\t   NULL, \"cannot create hash rxq\");\n-\t\tgoto error;\n+\t\trte_flow->hrxq = mlx5_priv_hrxq_new(priv, rss_hash_default_key,\n+\t\t\t\t\t\t    rss_hash_default_key_len,\n+\t\t\t\t\t\t    flow->hash_fields,\n+\t\t\t\t\t\t    flow->actions.queues,\n+\t\t\t\t\t\t    flow->actions.queues_n);\n+\t\tif (!rte_flow->hrxq) {\n+\t\t\trte_flow_error_set(error, ENOMEM,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE,\n+\t\t\t\t\t   NULL, \"cannot create hash rxq\");\n+\t\t\tgoto error;\n+\t\t}\n \t}\n \tfor (i = 0; i != flow->actions.queues_n; ++i) {\n \t\tstruct mlx5_rxq_data *q = (*priv->rxqs)[flow->actions.queues[i]];\n@@ -1448,7 +1446,7 @@ mlx5_flow_ctrl(struct rte_eth_dev *dev,\n \tif (enable) {\n \t\tflow = priv_flow_create(priv, &attr, items, actions, &error);\n \t\tif (!flow) {\n-\t\t\treturn 1;\n+\t\t\treturn rte_errno;\n \t\t}\n \t\tTAILQ_INSERT_TAIL(&priv->ctrl_flows, flow, next);\n \t\tDEBUG(\"Control flow created %p\", (void *)flow);\ndiff --git a/drivers/net/mlx5/mlx5_mac.c b/drivers/net/mlx5/mlx5_mac.c\nindex 45d23e4..ca26bcc 100644\n--- a/drivers/net/mlx5/mlx5_mac.c\n+++ b/drivers/net/mlx5/mlx5_mac.c\n@@ -83,112 +83,6 @@ priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN])\n }\n \n /**\n- * Delete MAC flow steering rule.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- * @param mac_index\n- *   MAC address index.\n- * @param vlan_index\n- *   VLAN index to use.\n- */\n-static void\n-hash_rxq_del_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index,\n-\t\t      unsigned int vlan_index)\n-{\n-#ifndef NDEBUG\n-\tconst uint8_t (*mac)[ETHER_ADDR_LEN] =\n-\t\t(const uint8_t (*)[ETHER_ADDR_LEN])\n-\t\thash_rxq->priv->mac[mac_index].addr_bytes;\n-#endif\n-\n-\tassert(mac_index < RTE_DIM(hash_rxq->mac_flow));\n-\tassert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index]));\n-\tif (hash_rxq->mac_flow[mac_index][vlan_index] == NULL)\n-\t\treturn;\n-\tDEBUG(\"%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u\"\n-\t      \" VLAN index %u\",\n-\t      (void *)hash_rxq,\n-\t      (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],\n-\t      mac_index,\n-\t      vlan_index);\n-\tclaim_zero(ibv_exp_destroy_flow(hash_rxq->mac_flow\n-\t\t\t\t\t[mac_index][vlan_index]));\n-\thash_rxq->mac_flow[mac_index][vlan_index] = NULL;\n-}\n-\n-/**\n- * Unregister a MAC address from a hash RX queue.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- * @param mac_index\n- *   MAC address index.\n- */\n-static void\n-hash_rxq_mac_addr_del(struct hash_rxq *hash_rxq, unsigned int mac_index)\n-{\n-\tunsigned int i;\n-\n-\tassert(mac_index < RTE_DIM(hash_rxq->mac_flow));\n-\tfor (i = 0; (i != RTE_DIM(hash_rxq->mac_flow[mac_index])); ++i)\n-\t\thash_rxq_del_mac_flow(hash_rxq, mac_index, i);\n-}\n-\n-/**\n- * Unregister all MAC addresses from a hash RX queue.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- */\n-void\n-hash_rxq_mac_addrs_del(struct hash_rxq *hash_rxq)\n-{\n-\tunsigned int i;\n-\n-\tfor (i = 0; (i != RTE_DIM(hash_rxq->mac_flow)); ++i)\n-\t\thash_rxq_mac_addr_del(hash_rxq, i);\n-}\n-\n-/**\n- * Unregister a MAC address.\n- *\n- * This is done for each hash RX queue.\n- *\n- * @param priv\n- *   Pointer to private structure.\n- * @param mac_index\n- *   MAC address index.\n- */\n-static void\n-priv_mac_addr_del(struct priv *priv, unsigned int mac_index)\n-{\n-\tunsigned int i;\n-\n-\tassert(mac_index < RTE_DIM(priv->mac));\n-\tif (!BITFIELD_ISSET(priv->mac_configured, mac_index))\n-\t\treturn;\n-\tfor (i = 0; (i != priv->hash_rxqs_n); ++i)\n-\t\thash_rxq_mac_addr_del(&(*priv->hash_rxqs)[i], mac_index);\n-\tBITFIELD_RESET(priv->mac_configured, mac_index);\n-}\n-\n-/**\n- * Unregister all MAC addresses from all hash RX queues.\n- *\n- * @param priv\n- *   Pointer to private structure.\n- */\n-void\n-priv_mac_addrs_disable(struct priv *priv)\n-{\n-\tunsigned int i;\n-\n-\tfor (i = 0; (i != priv->hash_rxqs_n); ++i)\n-\t\thash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[i]);\n-}\n-\n-/**\n  * DPDK callback to remove a MAC address.\n  *\n  * @param dev\n@@ -199,258 +93,12 @@ priv_mac_addrs_disable(struct priv *priv)\n void\n mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)\n {\n-\tstruct priv *priv = dev->data->dev_private;\n-\n \tif (mlx5_is_secondary())\n \t\treturn;\n-\n-\tpriv_lock(priv);\n-\tDEBUG(\"%p: removing MAC address from index %\" PRIu32,\n-\t      (void *)dev, index);\n-\tif (index >= RTE_DIM(priv->mac))\n-\t\tgoto end;\n-\tpriv_mac_addr_del(priv, index);\n-end:\n-\tpriv_unlock(priv);\n-}\n-\n-/**\n- * Add MAC flow steering rule.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- * @param mac_index\n- *   MAC address index to register.\n- * @param vlan_index\n- *   VLAN index to use.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-static int\n-hash_rxq_add_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index,\n-\t\t      unsigned int vlan_index)\n-{\n-\tstruct ibv_exp_flow *flow;\n-\tstruct priv *priv = hash_rxq->priv;\n-\tconst uint8_t (*mac)[ETHER_ADDR_LEN] =\n-\t\t\t(const uint8_t (*)[ETHER_ADDR_LEN])\n-\t\t\tpriv->mac[mac_index].addr_bytes;\n-\tFLOW_ATTR_SPEC_ETH(data, priv_flow_attr(priv, NULL, 0, hash_rxq->type));\n-\tstruct ibv_exp_flow_attr *attr = &data->attr;\n-\tstruct ibv_exp_flow_spec_eth *spec = &data->spec;\n-\tunsigned int vlan_enabled = !!priv->vlan_filter_n;\n-\tunsigned int vlan_id = priv->vlan_filter[vlan_index];\n-\n-\tassert(mac_index < RTE_DIM(hash_rxq->mac_flow));\n-\tassert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index]));\n-\tif (hash_rxq->mac_flow[mac_index][vlan_index] != NULL)\n-\t\treturn 0;\n-\t/*\n-\t * No padding must be inserted by the compiler between attr and spec.\n-\t * This layout is expected by libibverbs.\n-\t */\n-\tassert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec);\n-\tpriv_flow_attr(priv, attr, sizeof(data), hash_rxq->type);\n-\t/* The first specification must be Ethernet. */\n-\tassert(spec->type == IBV_EXP_FLOW_SPEC_ETH);\n-\tassert(spec->size == sizeof(*spec));\n-\t*spec = (struct ibv_exp_flow_spec_eth){\n-\t\t.type = IBV_EXP_FLOW_SPEC_ETH,\n-\t\t.size = sizeof(*spec),\n-\t\t.val = {\n-\t\t\t.dst_mac = {\n-\t\t\t\t(*mac)[0], (*mac)[1], (*mac)[2],\n-\t\t\t\t(*mac)[3], (*mac)[4], (*mac)[5]\n-\t\t\t},\n-\t\t\t.vlan_tag = (vlan_enabled ? htons(vlan_id) : 0),\n-\t\t},\n-\t\t.mask = {\n-\t\t\t.dst_mac = \"\\xff\\xff\\xff\\xff\\xff\\xff\",\n-\t\t\t.vlan_tag = (vlan_enabled ? htons(0xfff) : 0),\n-\t\t},\n-\t};\n-\tDEBUG(\"%p: adding MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u\"\n-\t      \" VLAN index %u filtering %s, ID %u\",\n-\t      (void *)hash_rxq,\n-\t      (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],\n-\t      mac_index,\n-\t      vlan_index,\n-\t      (vlan_enabled ? \"enabled\" : \"disabled\"),\n-\t      vlan_id);\n-\t/* Create related flow. */\n-\terrno = 0;\n-\tflow = ibv_exp_create_flow(hash_rxq->qp, attr);\n-\tif (flow == NULL) {\n-\t\t/* It's not clear whether errno is always set in this case. */\n-\t\tERROR(\"%p: flow configuration failed, errno=%d: %s\",\n-\t\t      (void *)hash_rxq, errno,\n-\t\t      (errno ? strerror(errno) : \"Unknown error\"));\n-\t\tif (errno)\n-\t\t\treturn errno;\n-\t\treturn EINVAL;\n-\t}\n-\thash_rxq->mac_flow[mac_index][vlan_index] = flow;\n-\treturn 0;\n-}\n-\n-/**\n- * Register a MAC address in a hash RX queue.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- * @param mac_index\n- *   MAC address index to register.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-static int\n-hash_rxq_mac_addr_add(struct hash_rxq *hash_rxq, unsigned int mac_index)\n-{\n-\tstruct priv *priv = hash_rxq->priv;\n-\tunsigned int i = 0;\n-\tint ret;\n-\n-\tassert(mac_index < RTE_DIM(hash_rxq->mac_flow));\n-\tassert(RTE_DIM(hash_rxq->mac_flow[mac_index]) ==\n-\t       RTE_DIM(priv->vlan_filter));\n-\t/* Add a MAC address for each VLAN filter, or at least once. */\n-\tdo {\n-\t\tret = hash_rxq_add_mac_flow(hash_rxq, mac_index, i);\n-\t\tif (ret) {\n-\t\t\t/* Failure, rollback. */\n-\t\t\twhile (i != 0)\n-\t\t\t\thash_rxq_del_mac_flow(hash_rxq, mac_index,\n-\t\t\t\t\t\t      --i);\n-\t\t\treturn ret;\n-\t\t}\n-\t} while (++i < priv->vlan_filter_n);\n-\treturn 0;\n-}\n-\n-/**\n- * Register all MAC addresses in a hash RX queue.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-int\n-hash_rxq_mac_addrs_add(struct hash_rxq *hash_rxq)\n-{\n-\tstruct priv *priv = hash_rxq->priv;\n-\tunsigned int i;\n-\tint ret;\n-\n-\tassert(RTE_DIM(priv->mac) == RTE_DIM(hash_rxq->mac_flow));\n-\tfor (i = 0; (i != RTE_DIM(priv->mac)); ++i) {\n-\t\tif (!BITFIELD_ISSET(priv->mac_configured, i))\n-\t\t\tcontinue;\n-\t\tret = hash_rxq_mac_addr_add(hash_rxq, i);\n-\t\tif (!ret)\n-\t\t\tcontinue;\n-\t\t/* Failure, rollback. */\n-\t\twhile (i != 0)\n-\t\t\thash_rxq_mac_addr_del(hash_rxq, --i);\n-\t\tassert(ret > 0);\n-\t\treturn ret;\n-\t}\n-\treturn 0;\n-}\n-\n-/**\n- * Register a MAC address.\n- *\n- * This is done for each hash RX queue.\n- *\n- * @param priv\n- *   Pointer to private structure.\n- * @param mac_index\n- *   MAC address index to use.\n- * @param mac\n- *   MAC address to register.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-int\n-priv_mac_addr_add(struct priv *priv, unsigned int mac_index,\n-\t\t  const uint8_t (*mac)[ETHER_ADDR_LEN])\n-{\n-\tunsigned int i;\n-\tint ret;\n-\n-\tassert(mac_index < RTE_DIM(priv->mac));\n-\t/* First, make sure this address isn't already configured. */\n-\tfor (i = 0; (i != RTE_DIM(priv->mac)); ++i) {\n-\t\t/* Skip this index, it's going to be reconfigured. */\n-\t\tif (i == mac_index)\n-\t\t\tcontinue;\n-\t\tif (!BITFIELD_ISSET(priv->mac_configured, i))\n-\t\t\tcontinue;\n-\t\tif (memcmp(priv->mac[i].addr_bytes, *mac, sizeof(*mac)))\n-\t\t\tcontinue;\n-\t\t/* Address already configured elsewhere, return with error. */\n-\t\treturn EADDRINUSE;\n-\t}\n-\tif (BITFIELD_ISSET(priv->mac_configured, mac_index))\n-\t\tpriv_mac_addr_del(priv, mac_index);\n-\tpriv->mac[mac_index] = (struct ether_addr){\n-\t\t{\n-\t\t\t(*mac)[0], (*mac)[1], (*mac)[2],\n-\t\t\t(*mac)[3], (*mac)[4], (*mac)[5]\n-\t\t}\n-\t};\n-\tif (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC))\n-\t\tgoto end;\n-\tfor (i = 0; (i != priv->hash_rxqs_n); ++i) {\n-\t\tret = hash_rxq_mac_addr_add(&(*priv->hash_rxqs)[i], mac_index);\n-\t\tif (!ret)\n-\t\t\tcontinue;\n-\t\t/* Failure, rollback. */\n-\t\twhile (i != 0)\n-\t\t\thash_rxq_mac_addr_del(&(*priv->hash_rxqs)[--i],\n-\t\t\t\t\t      mac_index);\n-\t\treturn ret;\n-\t}\n-end:\n-\tBITFIELD_SET(priv->mac_configured, mac_index);\n-\treturn 0;\n-}\n-\n-/**\n- * Register all MAC addresses in all hash RX queues.\n- *\n- * @param priv\n- *   Pointer to private structure.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-int\n-priv_mac_addrs_enable(struct priv *priv)\n-{\n-\tunsigned int i;\n-\tint ret;\n-\n-\tif (priv->isolated)\n-\t\treturn 0;\n-\tif (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC))\n-\t\treturn 0;\n-\tfor (i = 0; (i != priv->hash_rxqs_n); ++i) {\n-\t\tret = hash_rxq_mac_addrs_add(&(*priv->hash_rxqs)[i]);\n-\t\tif (!ret)\n-\t\t\tcontinue;\n-\t\t/* Failure, rollback. */\n-\t\twhile (i != 0)\n-\t\t\thash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[--i]);\n-\t\tassert(ret > 0);\n-\t\treturn ret;\n-\t}\n-\treturn 0;\n+\tassert(index < RTE_DIM(dev->data->mac_addrs));\n+\tmemset(&dev->data->mac_addrs[index], 0, sizeof(struct ether_addr));\n+\tif (!dev->data->promiscuous && !dev->data->all_multicast)\n+\t\tmlx5_traffic_restart(dev);\n }\n \n /**\n@@ -464,31 +112,35 @@ priv_mac_addrs_enable(struct priv *priv)\n  *   MAC address index.\n  * @param vmdq\n  *   VMDq pool index to associate address with (ignored).\n+ *\n+ * @return\n+ *   0 on success.\n  */\n int\n-mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,\n+mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac,\n \t\t  uint32_t index, uint32_t vmdq)\n {\n-\tstruct priv *priv = dev->data->dev_private;\n-\tint re;\n-\n-\tif (mlx5_is_secondary())\n-\t\treturn -ENOTSUP;\n+\tunsigned int i;\n+\tint ret = 0;\n \n \t(void)vmdq;\n-\tpriv_lock(priv);\n-\tDEBUG(\"%p: adding MAC address at index %\" PRIu32,\n-\t      (void *)dev, index);\n-\tif (index >= RTE_DIM(priv->mac)) {\n-\t\tre = EINVAL;\n-\t\tgoto end;\n+\tif (mlx5_is_secondary())\n+\t\treturn 0;\n+\tassert(index < RTE_DIM(dev->data->mac_addrs));\n+\t/* First, make sure this address isn't already configured. */\n+\tfor (i = 0; (i != RTE_DIM(dev->data->mac_addrs)); ++i) {\n+\t\t/* Skip this index, it's going to be reconfigured. */\n+\t\tif (i == index)\n+\t\t\tcontinue;\n+\t\tif (memcmp(&dev->data->mac_addrs[i], mac, sizeof(*mac)))\n+\t\t\tcontinue;\n+\t\t/* Address already configured elsewhere, return with error. */\n+\t\treturn EADDRINUSE;\n \t}\n-\tre = priv_mac_addr_add(priv, index,\n-\t\t\t       (const uint8_t (*)[ETHER_ADDR_LEN])\n-\t\t\t       mac_addr->addr_bytes);\n-end:\n-\tpriv_unlock(priv);\n-\treturn -re;\n+\tdev->data->mac_addrs[index] = *mac;\n+\tif (!dev->data->promiscuous && !dev->data->all_multicast)\n+\t\tmlx5_traffic_restart(dev);\n+\treturn ret;\n }\n \n /**\n@@ -502,7 +154,8 @@ mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,\n void\n mlx5_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)\n {\n+\tif (mlx5_is_secondary())\n+\t\treturn;\n \tDEBUG(\"%p: setting primary MAC address\", (void *)dev);\n-\tmlx5_mac_addr_remove(dev, 0);\n \tmlx5_mac_addr_add(dev, mac_addr, 0, 0);\n }\ndiff --git a/drivers/net/mlx5/mlx5_rxmode.c b/drivers/net/mlx5/mlx5_rxmode.c\nindex 3fcfec7..0ef2cdf 100644\n--- a/drivers/net/mlx5/mlx5_rxmode.c\n+++ b/drivers/net/mlx5/mlx5_rxmode.c\n@@ -51,304 +51,6 @@\n #include \"mlx5_rxtx.h\"\n #include \"mlx5_utils.h\"\n \n-/* Initialization data for special flows. */\n-static const struct special_flow_init special_flow_init[] = {\n-\t[HASH_RXQ_FLOW_TYPE_BROADCAST] = {\n-\t\t.dst_mac_val = \"\\xff\\xff\\xff\\xff\\xff\\xff\",\n-\t\t.dst_mac_mask = \"\\xff\\xff\\xff\\xff\\xff\\xff\",\n-\t\t.hash_types =\n-\t\t\t1 << HASH_RXQ_UDPV4 |\n-\t\t\t1 << HASH_RXQ_IPV4 |\n-\t\t\t1 << HASH_RXQ_UDPV6 |\n-\t\t\t1 << HASH_RXQ_IPV6 |\n-\t\t\t1 << HASH_RXQ_ETH |\n-\t\t\t0,\n-\t\t.per_vlan = 1,\n-\t},\n-\t[HASH_RXQ_FLOW_TYPE_IPV6MULTI] = {\n-\t\t.dst_mac_val = \"\\x33\\x33\\x00\\x00\\x00\\x00\",\n-\t\t.dst_mac_mask = \"\\xff\\xff\\x00\\x00\\x00\\x00\",\n-\t\t.hash_types =\n-\t\t\t1 << HASH_RXQ_UDPV6 |\n-\t\t\t1 << HASH_RXQ_IPV6 |\n-\t\t\t1 << HASH_RXQ_ETH |\n-\t\t\t0,\n-\t\t.per_vlan = 1,\n-\t},\n-};\n-\n-/**\n- * Enable a special flow in a hash RX queue for a given VLAN index.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- * @param flow_type\n- *   Special flow type.\n- * @param vlan_index\n- *   VLAN index to use.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-static int\n-hash_rxq_special_flow_enable_vlan(struct hash_rxq *hash_rxq,\n-\t\t\t\t  enum hash_rxq_flow_type flow_type,\n-\t\t\t\t  unsigned int vlan_index)\n-{\n-\tstruct priv *priv = hash_rxq->priv;\n-\tstruct ibv_exp_flow *flow;\n-\tFLOW_ATTR_SPEC_ETH(data, priv_flow_attr(priv, NULL, 0, hash_rxq->type));\n-\tstruct ibv_exp_flow_attr *attr = &data->attr;\n-\tstruct ibv_exp_flow_spec_eth *spec = &data->spec;\n-\tconst uint8_t *mac;\n-\tconst uint8_t *mask;\n-\tunsigned int vlan_enabled = (priv->vlan_filter_n &&\n-\t\t\t\t     special_flow_init[flow_type].per_vlan);\n-\tunsigned int vlan_id = priv->vlan_filter[vlan_index];\n-\n-\t/* Check if flow is relevant for this hash_rxq. */\n-\tif (!(special_flow_init[flow_type].hash_types & (1 << hash_rxq->type)))\n-\t\treturn 0;\n-\t/* Check if flow already exists. */\n-\tif (hash_rxq->special_flow[flow_type][vlan_index] != NULL)\n-\t\treturn 0;\n-\n-\t/*\n-\t * No padding must be inserted by the compiler between attr and spec.\n-\t * This layout is expected by libibverbs.\n-\t */\n-\tassert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec);\n-\tpriv_flow_attr(priv, attr, sizeof(data), hash_rxq->type);\n-\t/* The first specification must be Ethernet. */\n-\tassert(spec->type == IBV_EXP_FLOW_SPEC_ETH);\n-\tassert(spec->size == sizeof(*spec));\n-\n-\tmac = special_flow_init[flow_type].dst_mac_val;\n-\tmask = special_flow_init[flow_type].dst_mac_mask;\n-\t*spec = (struct ibv_exp_flow_spec_eth){\n-\t\t.type = IBV_EXP_FLOW_SPEC_ETH,\n-\t\t.size = sizeof(*spec),\n-\t\t.val = {\n-\t\t\t.dst_mac = {\n-\t\t\t\tmac[0], mac[1], mac[2],\n-\t\t\t\tmac[3], mac[4], mac[5],\n-\t\t\t},\n-\t\t\t.vlan_tag = (vlan_enabled ? htons(vlan_id) : 0),\n-\t\t},\n-\t\t.mask = {\n-\t\t\t.dst_mac = {\n-\t\t\t\tmask[0], mask[1], mask[2],\n-\t\t\t\tmask[3], mask[4], mask[5],\n-\t\t\t},\n-\t\t\t.vlan_tag = (vlan_enabled ? htons(0xfff) : 0),\n-\t\t},\n-\t};\n-\n-\terrno = 0;\n-\tflow = ibv_exp_create_flow(hash_rxq->qp, attr);\n-\tif (flow == NULL) {\n-\t\t/* It's not clear whether errno is always set in this case. */\n-\t\tERROR(\"%p: flow configuration failed, errno=%d: %s\",\n-\t\t      (void *)hash_rxq, errno,\n-\t\t      (errno ? strerror(errno) : \"Unknown error\"));\n-\t\tif (errno)\n-\t\t\treturn errno;\n-\t\treturn EINVAL;\n-\t}\n-\thash_rxq->special_flow[flow_type][vlan_index] = flow;\n-\tDEBUG(\"%p: special flow %s (index %d) VLAN %u (index %u) enabled\",\n-\t      (void *)hash_rxq, hash_rxq_flow_type_str(flow_type), flow_type,\n-\t      vlan_id, vlan_index);\n-\treturn 0;\n-}\n-\n-/**\n- * Disable a special flow in a hash RX queue for a given VLAN index.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- * @param flow_type\n- *   Special flow type.\n- * @param vlan_index\n- *   VLAN index to use.\n- */\n-static void\n-hash_rxq_special_flow_disable_vlan(struct hash_rxq *hash_rxq,\n-\t\t\t\t   enum hash_rxq_flow_type flow_type,\n-\t\t\t\t   unsigned int vlan_index)\n-{\n-\tstruct ibv_exp_flow *flow =\n-\t\thash_rxq->special_flow[flow_type][vlan_index];\n-\n-\tif (flow == NULL)\n-\t\treturn;\n-\tclaim_zero(ibv_exp_destroy_flow(flow));\n-\thash_rxq->special_flow[flow_type][vlan_index] = NULL;\n-\tDEBUG(\"%p: special flow %s (index %d) VLAN %u (index %u) disabled\",\n-\t      (void *)hash_rxq, hash_rxq_flow_type_str(flow_type), flow_type,\n-\t      hash_rxq->priv->vlan_filter[vlan_index], vlan_index);\n-}\n-\n-/**\n- * Enable a special flow in a hash RX queue.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- * @param flow_type\n- *   Special flow type.\n- * @param vlan_index\n- *   VLAN index to use.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-static int\n-hash_rxq_special_flow_enable(struct hash_rxq *hash_rxq,\n-\t\t\t     enum hash_rxq_flow_type flow_type)\n-{\n-\tstruct priv *priv = hash_rxq->priv;\n-\tunsigned int i = 0;\n-\tint ret;\n-\n-\tassert((unsigned int)flow_type < RTE_DIM(hash_rxq->special_flow));\n-\tassert(RTE_DIM(hash_rxq->special_flow[flow_type]) ==\n-\t       RTE_DIM(priv->vlan_filter));\n-\t/* Add a special flow for each VLAN filter when relevant. */\n-\tdo {\n-\t\tret = hash_rxq_special_flow_enable_vlan(hash_rxq, flow_type, i);\n-\t\tif (ret) {\n-\t\t\t/* Failure, rollback. */\n-\t\t\twhile (i != 0)\n-\t\t\t\thash_rxq_special_flow_disable_vlan(hash_rxq,\n-\t\t\t\t\t\t\t\t   flow_type,\n-\t\t\t\t\t\t\t\t   --i);\n-\t\t\treturn ret;\n-\t\t}\n-\t} while (special_flow_init[flow_type].per_vlan &&\n-\t\t ++i < priv->vlan_filter_n);\n-\treturn 0;\n-}\n-\n-/**\n- * Disable a special flow in a hash RX queue.\n- *\n- * @param hash_rxq\n- *   Pointer to hash RX queue structure.\n- * @param flow_type\n- *   Special flow type.\n- */\n-static void\n-hash_rxq_special_flow_disable(struct hash_rxq *hash_rxq,\n-\t\t\t      enum hash_rxq_flow_type flow_type)\n-{\n-\tunsigned int i;\n-\n-\tassert((unsigned int)flow_type < RTE_DIM(hash_rxq->special_flow));\n-\tfor (i = 0; (i != RTE_DIM(hash_rxq->special_flow[flow_type])); ++i)\n-\t\thash_rxq_special_flow_disable_vlan(hash_rxq, flow_type, i);\n-}\n-\n-/**\n- * Enable a special flow in all hash RX queues.\n- *\n- * @param priv\n- *   Private structure.\n- * @param flow_type\n- *   Special flow type.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-int\n-priv_special_flow_enable(struct priv *priv, enum hash_rxq_flow_type flow_type)\n-{\n-\tunsigned int i;\n-\n-\tif (!priv_allow_flow_type(priv, flow_type))\n-\t\treturn 0;\n-\tfor (i = 0; (i != priv->hash_rxqs_n); ++i) {\n-\t\tstruct hash_rxq *hash_rxq = &(*priv->hash_rxqs)[i];\n-\t\tint ret;\n-\n-\t\tret = hash_rxq_special_flow_enable(hash_rxq, flow_type);\n-\t\tif (!ret)\n-\t\t\tcontinue;\n-\t\t/* Failure, rollback. */\n-\t\twhile (i != 0) {\n-\t\t\thash_rxq = &(*priv->hash_rxqs)[--i];\n-\t\t\thash_rxq_special_flow_disable(hash_rxq, flow_type);\n-\t\t}\n-\t\treturn ret;\n-\t}\n-\treturn 0;\n-}\n-\n-/**\n- * Disable a special flow in all hash RX queues.\n- *\n- * @param priv\n- *   Private structure.\n- * @param flow_type\n- *   Special flow type.\n- */\n-void\n-priv_special_flow_disable(struct priv *priv, enum hash_rxq_flow_type flow_type)\n-{\n-\tunsigned int i;\n-\n-\tfor (i = 0; (i != priv->hash_rxqs_n); ++i) {\n-\t\tstruct hash_rxq *hash_rxq = &(*priv->hash_rxqs)[i];\n-\n-\t\thash_rxq_special_flow_disable(hash_rxq, flow_type);\n-\t}\n-}\n-\n-/**\n- * Enable all special flows in all hash RX queues.\n- *\n- * @param priv\n- *   Private structure.\n- */\n-int\n-priv_special_flow_enable_all(struct priv *priv)\n-{\n-\tenum hash_rxq_flow_type flow_type;\n-\n-\tif (priv->isolated)\n-\t\treturn 0;\n-\tfor (flow_type = HASH_RXQ_FLOW_TYPE_BROADCAST;\n-\t\t\tflow_type != HASH_RXQ_FLOW_TYPE_MAC;\n-\t\t\t++flow_type) {\n-\t\tint ret;\n-\n-\t\tret = priv_special_flow_enable(priv, flow_type);\n-\t\tif (!ret)\n-\t\t\tcontinue;\n-\t\t/* Failure, rollback. */\n-\t\twhile (flow_type)\n-\t\t\tpriv_special_flow_disable(priv, --flow_type);\n-\t\treturn ret;\n-\t}\n-\treturn 0;\n-}\n-\n-/**\n- * Disable all special flows in all hash RX queues.\n- *\n- * @param priv\n- *   Private structure.\n- */\n-void\n-priv_special_flow_disable_all(struct priv *priv)\n-{\n-\tenum hash_rxq_flow_type flow_type;\n-\n-\tfor (flow_type = HASH_RXQ_FLOW_TYPE_BROADCAST;\n-\t\t\tflow_type != HASH_RXQ_FLOW_TYPE_MAC;\n-\t\t\t++flow_type)\n-\t\tpriv_special_flow_disable(priv, flow_type);\n-}\n-\n /**\n  * DPDK callback to enable promiscuous mode.\n  *\n@@ -358,16 +60,10 @@ priv_special_flow_disable_all(struct priv *priv)\n void\n mlx5_promiscuous_enable(struct rte_eth_dev *dev)\n {\n-\tstruct rte_flow_item_eth eth = {\n-\t\t.dst.addr_bytes = \"\\x00\\x00\\x00\\x00\\x00\\x00\",\n-\t\t.src.addr_bytes = \"\\x00\\x00\\x00\\x00\\x00\\x00\",\n-\t\t.type = 0,\n-\t};\n-\n \tif (mlx5_is_secondary())\n \t\treturn;\n \tdev->data->promiscuous = 1;\n-\tclaim_zero(mlx5_flow_ctrl(dev, &eth, &eth, 3, 1));\n+\tmlx5_traffic_restart(dev);\n }\n \n /**\n@@ -379,16 +75,10 @@ mlx5_promiscuous_enable(struct rte_eth_dev *dev)\n void\n mlx5_promiscuous_disable(struct rte_eth_dev *dev)\n {\n-\tstruct rte_flow_item_eth eth = {\n-\t\t.dst.addr_bytes = \"\\x00\\x00\\x00\\x00\\x00\\x00\",\n-\t\t.src.addr_bytes = \"\\x00\\x00\\x00\\x00\\x00\\x00\",\n-\t\t.type = 0,\n-\t};\n-\n \tif (mlx5_is_secondary())\n \t\treturn;\n \tdev->data->promiscuous = 0;\n-\tclaim_zero(mlx5_flow_ctrl(dev, &eth, &eth, 3, 0));\n+\tmlx5_traffic_restart(dev);\n }\n \n /**\n@@ -400,17 +90,10 @@ mlx5_promiscuous_disable(struct rte_eth_dev *dev)\n void\n mlx5_allmulticast_enable(struct rte_eth_dev *dev)\n {\n-\tstruct rte_flow_item_eth eth = {\n-\t\t.dst.addr_bytes = \"\\x01\\x00\\x00\\x00\\x00\\x00\",\n-\t\t.src.addr_bytes = \"\\x01\\x00\\x00\\x00\\x00\\x00\",\n-\t\t.type = 0,\n-\t};\n-\n \tif (mlx5_is_secondary())\n \t\treturn;\n \tdev->data->all_multicast = 1;\n-\tif (dev->data->dev_started)\n-\t\tclaim_zero(mlx5_flow_ctrl(dev, &eth, &eth, 3, 1));\n+\tmlx5_traffic_restart(dev);\n }\n \n /**\n@@ -422,15 +105,8 @@ mlx5_allmulticast_enable(struct rte_eth_dev *dev)\n void\n mlx5_allmulticast_disable(struct rte_eth_dev *dev)\n {\n-\tstruct rte_flow_item_eth eth = {\n-\t\t.dst.addr_bytes = \"\\x01\\x00\\x00\\x00\\x00\\x00\",\n-\t\t.src.addr_bytes = \"\\x01\\x00\\x00\\x00\\x00\\x00\",\n-\t\t.type = 0,\n-\t};\n-\n \tif (mlx5_is_secondary())\n \t\treturn;\n \tdev->data->all_multicast = 0;\n-\tif (dev->data->dev_started)\n-\t\tclaim_zero(mlx5_flow_ctrl(dev, &eth, &eth, 3, 0));\n+\tmlx5_traffic_restart(dev);\n }\ndiff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c\nindex e5ec57f..438db07 100644\n--- a/drivers/net/mlx5/mlx5_rxq.c\n+++ b/drivers/net/mlx5/mlx5_rxq.c\n@@ -533,12 +533,6 @@ priv_destroy_hash_rxqs(struct priv *priv)\n \n \t\tassert(hash_rxq->priv == priv);\n \t\tassert(hash_rxq->qp != NULL);\n-\t\t/* Also check that there are no remaining flows. */\n-\t\tfor (j = 0; (j != RTE_DIM(hash_rxq->special_flow)); ++j)\n-\t\t\tfor (k = 0;\n-\t\t\t     (k != RTE_DIM(hash_rxq->special_flow[j]));\n-\t\t\t     ++k)\n-\t\t\t\tassert(hash_rxq->special_flow[j][k] == NULL);\n \t\tfor (j = 0; (j != RTE_DIM(hash_rxq->mac_flow)); ++j)\n \t\t\tfor (k = 0; (k != RTE_DIM(hash_rxq->mac_flow[j])); ++k)\n \t\t\t\tassert(hash_rxq->mac_flow[j][k] == NULL);\n@@ -560,65 +554,6 @@ priv_destroy_hash_rxqs(struct priv *priv)\n }\n \n /**\n- * Check whether a given flow type is allowed.\n- *\n- * @param priv\n- *   Pointer to private structure.\n- * @param type\n- *   Flow type to check.\n- *\n- * @return\n- *   Nonzero if the given flow type is allowed.\n- */\n-int\n-priv_allow_flow_type(struct priv *priv, enum hash_rxq_flow_type type)\n-{\n-\t(void)priv;\n-\tswitch (type) {\n-\tcase HASH_RXQ_FLOW_TYPE_BROADCAST:\n-\tcase HASH_RXQ_FLOW_TYPE_IPV6MULTI:\n-\tcase HASH_RXQ_FLOW_TYPE_MAC:\n-\t\treturn 1;\n-\t\treturn 1;\n-\tdefault:\n-\t\t/* Unsupported flow type is not allowed. */\n-\t\treturn 0;\n-\t}\n-\treturn 0;\n-}\n-\n-/**\n- * Automatically enable/disable flows according to configuration.\n- *\n- * @param priv\n- *   Private structure.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-int\n-priv_rehash_flows(struct priv *priv)\n-{\n-\tenum hash_rxq_flow_type i;\n-\n-\tfor (i = HASH_RXQ_FLOW_TYPE_BROADCAST;\n-\t\t\ti != RTE_DIM((*priv->hash_rxqs)[0].special_flow);\n-\t\t\t++i)\n-\t\tif (!priv_allow_flow_type(priv, i)) {\n-\t\t\tpriv_special_flow_disable(priv, i);\n-\t\t} else {\n-\t\t\tint ret = priv_special_flow_enable(priv, i);\n-\n-\t\t\tif (ret)\n-\t\t\t\treturn ret;\n-\t\t}\n-\tif (priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC))\n-\t\treturn priv_mac_addrs_enable(priv);\n-\tpriv_mac_addrs_disable(priv);\n-\treturn 0;\n-}\n-\n-/**\n  * Allocate RX queue elements.\n  *\n  * @param rxq_ctrl\ndiff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h\nindex 4d26726..683a866 100644\n--- a/drivers/net/mlx5/mlx5_rxtx.h\n+++ b/drivers/net/mlx5/mlx5_rxtx.h\n@@ -232,28 +232,6 @@ struct special_flow_init {\n \tunsigned int per_vlan:1;\n };\n \n-enum hash_rxq_flow_type {\n-\tHASH_RXQ_FLOW_TYPE_BROADCAST,\n-\tHASH_RXQ_FLOW_TYPE_IPV6MULTI,\n-\tHASH_RXQ_FLOW_TYPE_MAC,\n-};\n-\n-#ifndef NDEBUG\n-static inline const char *\n-hash_rxq_flow_type_str(enum hash_rxq_flow_type flow_type)\n-{\n-\tswitch (flow_type) {\n-\tcase HASH_RXQ_FLOW_TYPE_BROADCAST:\n-\t\treturn \"broadcast\";\n-\tcase HASH_RXQ_FLOW_TYPE_IPV6MULTI:\n-\t\treturn \"IPv6 multicast\";\n-\tcase HASH_RXQ_FLOW_TYPE_MAC:\n-\t\treturn \"MAC\";\n-\t}\n-\treturn NULL;\n-}\n-#endif /* NDEBUG */\n-\n struct hash_rxq {\n \tstruct priv *priv; /* Back pointer to private data. */\n \tstruct ibv_qp *qp; /* Hash RX QP. */\n@@ -261,8 +239,6 @@ struct hash_rxq {\n \t/* MAC flow steering rules, one per VLAN ID. */\n \tstruct ibv_exp_flow *mac_flow\n \t\t[MLX5_MAX_MAC_ADDRESSES][MLX5_MAX_VLAN_IDS];\n-\tstruct ibv_exp_flow *special_flow\n-\t\t[MLX5_MAX_SPECIAL_FLOWS][MLX5_MAX_VLAN_IDS];\n };\n \n /* TX queue descriptor. */\n@@ -331,8 +307,6 @@ size_t priv_flow_attr(struct priv *, struct ibv_exp_flow_attr *,\n \t\t      size_t, enum hash_rxq_type);\n int priv_create_hash_rxqs(struct priv *);\n void priv_destroy_hash_rxqs(struct priv *);\n-int priv_allow_flow_type(struct priv *, enum hash_rxq_flow_type);\n-int priv_rehash_flows(struct priv *);\n void mlx5_rxq_cleanup(struct mlx5_rxq_ctrl *);\n int mlx5_rxq_ctrl_setup(struct rte_eth_dev *, struct mlx5_rxq_ctrl *,\n \t\t\tuint16_t, unsigned int, const struct rte_eth_rxconf *,\ndiff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c\nindex 6370d6f..28f59dc 100644\n--- a/drivers/net/mlx5/mlx5_trigger.c\n+++ b/drivers/net/mlx5/mlx5_trigger.c\n@@ -134,6 +134,7 @@ mlx5_dev_start(struct rte_eth_dev *dev)\n \tif (mlx5_is_secondary())\n \t\treturn -E_RTE_SECONDARY;\n \n+\tdev->data->dev_started = 1;\n \tpriv_lock(priv);\n \t/* Update Rx/Tx callback. */\n \tpriv_select_tx_function(priv);\n@@ -157,21 +158,8 @@ mlx5_dev_start(struct rte_eth_dev *dev)\n \t/* Update receive callback. */\n \tpriv_select_rx_function(priv);\n \terr = priv_create_hash_rxqs(priv);\n-\tif (!err)\n-\t\terr = priv_rehash_flows(priv);\n-\telse {\n-\t\tERROR(\"%p: an error occurred while configuring hash RX queues:\"\n-\t\t      \" %s\",\n-\t\t      (void *)priv, strerror(err));\n-\t\tgoto error;\n-\t}\n-\tif (dev->data->promiscuous)\n-\t       mlx5_promiscuous_enable(dev);\n-\telse if (dev->data->all_multicast)\n-\t\tmlx5_allmulticast_enable(dev);\n-\terr = priv_flow_start(priv, &priv->ctrl_flows);\n \tif (err) {\n-\t\tERROR(\"%p: an error occurred while configuring control flows:\"\n+\t\tERROR(\"%p: an error occurred while configuring hash RX queues:\"\n \t\t      \" %s\",\n \t\t      (void *)priv, strerror(err));\n \t\tgoto error;\n@@ -195,15 +183,13 @@ mlx5_dev_start(struct rte_eth_dev *dev)\n \treturn 0;\n error:\n \t/* Rollback. */\n+\tdev->data->dev_started = 0;\n \tLIST_FOREACH(mr, &priv->mr, next)\n \t\tpriv_mr_release(priv, mr);\n-\tpriv_special_flow_disable_all(priv);\n-\tpriv_mac_addrs_disable(priv);\n \tpriv_destroy_hash_rxqs(priv);\n \tpriv_flow_stop(priv, &priv->flows);\n-\tpriv_flow_flush(priv, &priv->ctrl_flows);\n-\tpriv_rxq_stop(priv);\n \tpriv_txq_stop(priv);\n+\tpriv_rxq_stop(priv);\n \tpriv_unlock(priv);\n \treturn -err;\n }\n@@ -227,8 +213,6 @@ mlx5_dev_stop(struct rte_eth_dev *dev)\n \n \tpriv_lock(priv);\n \tDEBUG(\"%p: cleaning up and destroying hash RX queues\", (void *)dev);\n-\tpriv_special_flow_disable_all(priv);\n-\tpriv_mac_addrs_disable(priv);\n \tpriv_destroy_hash_rxqs(priv);\n \tpriv_flow_stop(priv, &priv->flows);\n \tpriv_flow_flush(priv, &priv->ctrl_flows);\n@@ -240,3 +224,160 @@ mlx5_dev_stop(struct rte_eth_dev *dev)\n \tpriv_rx_intr_vec_disable(priv);\n \tpriv_unlock(priv);\n }\n+\n+/**\n+ * Enable traffic flows configured by control plane\n+ *\n+ * @param priv\n+ *   Pointer to Ethernet device private data.\n+ * @param dev\n+ *   Pointer to Ethernet device structure.\n+ *\n+ * @return\n+ *   0 on success.\n+ */\n+int\n+priv_dev_traffic_enable(struct priv *priv, struct rte_eth_dev *dev)\n+{\n+\tif (dev->data->promiscuous) {\n+\t\tstruct rte_flow_item_eth eth = {\n+\t\t\t.dst.addr_bytes = \"\\x00\\x00\\x00\\x00\\x00\\x00\",\n+\t\t\t.src.addr_bytes = \"\\x00\\x00\\x00\\x00\\x00\\x00\",\n+\t\t\t.type = 0,\n+\t\t};\n+\n+\t\tclaim_zero(mlx5_flow_ctrl(dev, &eth, &eth, 3, 1));\n+\t} else if (dev->data->all_multicast) {\n+\t\tstruct rte_flow_item_eth eth = {\n+\t\t\t.dst.addr_bytes = \"\\x01\\x00\\x00\\x00\\x00\\x00\",\n+\t\t\t.src.addr_bytes = \"\\x01\\x00\\x00\\x00\\x00\\x00\",\n+\t\t\t.type = 0,\n+\t\t};\n+\n+\t\tclaim_zero(mlx5_flow_ctrl(dev, &eth, &eth, 3, 1));\n+\t} else {\n+\t\tstruct rte_flow_item_eth bcast = {\n+\t\t\t.dst.addr_bytes = \"\\xff\\xff\\xff\\xff\\xff\\xff\",\n+\t\t};\n+\t\tstruct rte_flow_item_eth ipv6_spec = {\n+\t\t\t.dst.addr_bytes = \"\\x33\\x33\\x00\\x00\\x00\\x00\",\n+\t\t};\n+\t\tstruct rte_flow_item_eth ipv6_mask = {\n+\t\t\t.dst.addr_bytes = \"\\xff\\xff\\x00\\x00\\x00\\x00\",\n+\t\t};\n+\t\tstruct rte_flow_item_eth eth = {\n+\t\t\t.src.addr_bytes = \"\\x00\\x00\\x00\\x00\\x00\\x00\",\n+\t\t};\n+\t\tstruct rte_flow_item_eth mask = {\n+\t\t\t.dst.addr_bytes = \"\\xff\\xff\\xff\\xff\\xff\\xff\",\n+\t\t};\n+\t\tuint16_t ether_type = 0;\n+\t\tconst unsigned int vlan_filter_n = priv->vlan_filter_n;\n+\t\tconst struct ether_addr cmp = {\n+\t\t\t.addr_bytes = \"\\x00\\x00\\x00\\x00\\x00\\x00\",\n+\t\t};\n+\t\tunsigned int i;\n+\t\tunsigned int j;\n+\t\tunsigned int unicast = 0;\n+\t\tint ret;\n+\n+\t\tfor (i = 0; i != RTE_DIM(dev->data->mac_addrs); ++i) {\n+\t\t\tstruct ether_addr *mac = &dev->data->mac_addrs[i];\n+\n+\t\t\tif (!memcmp(mac, &cmp, sizeof(*mac)))\n+\t\t\t\tcontinue;\n+\t\t\tmemcpy(&eth.dst.addr_bytes,\n+\t\t\t       mac->addr_bytes,\n+\t\t\t       ETHER_ADDR_LEN);\n+\t\t\tfor (j = 0; j != vlan_filter_n; ++j) {\n+\t\t\t\tether_type = priv->vlan_filter[j];\n+\t\t\t\teth.type = ether_type;\n+\t\t\t\tmask.type = 0xffff;\n+\t\t\t\tret = mlx5_flow_ctrl(dev, &eth, &mask, 3, 1);\n+\t\t\t\tif (ret)\n+\t\t\t\t\tgoto error;\n+\t\t\t\tunicast = 1;\n+\t\t\t}\n+\t\t\tif (!vlan_filter_n) {\n+\t\t\t\tret = mlx5_flow_ctrl(dev, &eth, &mask, 3, 1);\n+\t\t\t\tif (ret)\n+\t\t\t\t\tgoto error;\n+\t\t\t\tunicast = 1;\n+\t\t\t}\n+\t\t}\n+\t\tif (!unicast)\n+\t\t\treturn 0;\n+\t\tret = mlx5_flow_ctrl(dev, &bcast, &bcast, 3, 1);\n+\t\tif (ret)\n+\t\t\tgoto error;\n+\t\tret = mlx5_flow_ctrl(dev, &ipv6_spec, &ipv6_mask, 3, 1);\n+\t\tif (ret)\n+\t\t\tgoto error;\n+\t}\n+\treturn 0;\n+error:\n+\treturn rte_errno;\n+}\n+\n+/**\n+ * Disable traffic flows configured by control plane\n+ *\n+ * @param priv\n+ *   Pointer to Ethernet device private data.\n+ * @param dev\n+ *   Pointer to Ethernet device structure.\n+ *\n+ * @return\n+ *   0 on success.\n+ */\n+int\n+priv_dev_traffic_disable(struct priv *priv, struct rte_eth_dev *dev)\n+{\n+\t(void)dev;\n+\tpriv_flow_flush(priv, &priv->ctrl_flows);\n+\treturn 0;\n+}\n+\n+/**\n+ * Restart traffic flows configured by control plane\n+ *\n+ * @param priv\n+ *   Pointer to Ethernet device private data.\n+ * @param dev\n+ *   Pointer to Ethernet device structure.\n+ *\n+ * @return\n+ *   0 on success.\n+ */\n+int\n+priv_dev_traffic_restart(struct priv *priv, struct rte_eth_dev *dev)\n+{\n+\tif (dev->data->dev_started) {\n+\t\tpriv_dev_traffic_disable(priv, dev);\n+\t\tpriv_dev_traffic_enable(priv, dev);\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * Restart traffic flows configured by control plane\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device structure.\n+ *\n+ * @return\n+ *   0 on success.\n+ */\n+int\n+mlx5_traffic_restart(struct rte_eth_dev *dev)\n+{\n+\tstruct priv *priv = dev->data->dev_private;\n+\n+\tpriv_lock(priv);\n+\tif (dev->data->dev_started) {\n+\t\tpriv_dev_traffic_disable(priv, dev);\n+\t\tpriv_dev_traffic_enable(priv, dev);\n+\t}\n+\tpriv_unlock(priv);\n+\treturn 0;\n+}\ndiff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c\nindex dffa1cd..c41c57b 100644\n--- a/drivers/net/mlx5/mlx5_vlan.c\n+++ b/drivers/net/mlx5/mlx5_vlan.c\n@@ -44,7 +44,7 @@\n #include \"mlx5_autoconf.h\"\n \n /**\n- * Configure a VLAN filter.\n+ * DPDK callback to configure a VLAN filter.\n  *\n  * @param dev\n  *   Pointer to Ethernet device structure.\n@@ -54,14 +54,16 @@\n  *   Toggle filter.\n  *\n  * @return\n- *   0 on success, errno value on failure.\n+ *   0 on success, negative errno value on failure.\n  */\n-static int\n-vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)\n+int\n+mlx5_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)\n {\n \tstruct priv *priv = dev->data->dev_private;\n \tunsigned int i;\n+\tint ret;\n \n+\tpriv_lock(priv);\n \tDEBUG(\"%p: %s VLAN filter ID %\" PRIu16,\n \t      (void *)dev, (on ? \"enable\" : \"disable\"), vlan_id);\n \tassert(priv->vlan_filter_n <= RTE_DIM(priv->vlan_filter));\n@@ -69,13 +71,15 @@ vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)\n \t\tif (priv->vlan_filter[i] == vlan_id)\n \t\t\tbreak;\n \t/* Check if there's room for another VLAN filter. */\n-\tif (i == RTE_DIM(priv->vlan_filter))\n-\t\treturn ENOMEM;\n+\tif (i == RTE_DIM(priv->vlan_filter)) {\n+\t\tret = -ENOMEM;\n+\t\tgoto out;\n+\t}\n \tif (i < priv->vlan_filter_n) {\n \t\tassert(priv->vlan_filter_n != 0);\n \t\t/* Enabling an existing VLAN filter has no effect. */\n \t\tif (on)\n-\t\t\treturn 0;\n+\t\t\tgoto out;\n \t\t/* Remove VLAN filter from list. */\n \t\t--priv->vlan_filter_n;\n \t\tmemmove(&priv->vlan_filter[i],\n@@ -87,41 +91,19 @@ vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)\n \t\tassert(i == priv->vlan_filter_n);\n \t\t/* Disabling an unknown VLAN filter has no effect. */\n \t\tif (!on)\n-\t\t\treturn 0;\n+\t\t\tgoto out;\n \t\t/* Add new VLAN filter. */\n \t\tpriv->vlan_filter[priv->vlan_filter_n] = vlan_id;\n \t\t++priv->vlan_filter_n;\n \t}\n-\t/* Rehash flows in all hash RX queues. */\n-\tpriv_mac_addrs_disable(priv);\n-\tpriv_special_flow_disable_all(priv);\n-\treturn priv_rehash_flows(priv);\n-}\n-\n-/**\n- * DPDK callback to configure a VLAN filter.\n- *\n- * @param dev\n- *   Pointer to Ethernet device structure.\n- * @param vlan_id\n- *   VLAN ID to filter.\n- * @param on\n- *   Toggle filter.\n- *\n- * @return\n- *   0 on success, negative errno value on failure.\n- */\n-int\n-mlx5_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)\n-{\n-\tstruct priv *priv = dev->data->dev_private;\n-\tint ret;\n-\n-\tpriv_lock(priv);\n-\tret = vlan_filter_set(dev, vlan_id, on);\n+\tif (dev->data->dev_started) {\n+\t\tpriv_dev_traffic_disable(priv, dev);\n+\t\tpriv_dev_traffic_enable(priv, dev);\n+\t}\n+out:\n \tpriv_unlock(priv);\n \tassert(ret >= 0);\n-\treturn -ret;\n+\treturn ret;\n }\n \n /**\n",
    "prefixes": [
        "dpdk-dev",
        "v1",
        "18/21"
    ]
}