get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 7430,
    "url": "http://patches.dpdk.org/api/patches/7430/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1444067589-29513-4-git-send-email-adrien.mazarguil@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": "<1444067589-29513-4-git-send-email-adrien.mazarguil@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1444067589-29513-4-git-send-email-adrien.mazarguil@6wind.com",
    "date": "2015-10-05T17:52:59",
    "name": "[dpdk-dev,03/13] mlx5: add MAC handling",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "29c90d6b5b58d1961c8dd2788bd59da7da93d389",
    "submitter": {
        "id": 165,
        "url": "http://patches.dpdk.org/api/people/165/?format=api",
        "name": "Adrien Mazarguil",
        "email": "adrien.mazarguil@6wind.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1444067589-29513-4-git-send-email-adrien.mazarguil@6wind.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/7430/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/7430/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 5B9179231;\n\tMon,  5 Oct 2015 19:53:43 +0200 (CEST)",
            "from mail-wi0-f177.google.com (mail-wi0-f177.google.com\n\t[209.85.212.177]) by dpdk.org (Postfix) with ESMTP id 2839E9221\n\tfor <dev@dpdk.org>; Mon,  5 Oct 2015 19:53:42 +0200 (CEST)",
            "by wicfx3 with SMTP id fx3so125719656wic.0\n\tfor <dev@dpdk.org>; Mon, 05 Oct 2015 10:53:42 -0700 (PDT)",
            "from 6wind.com (guy78-3-82-239-227-177.fbx.proxad.net.\n\t[82.239.227.177]) by smtp.gmail.com with ESMTPSA id\n\tgo5sm15846977wib.3.2015.10.05.10.53.41\n\t(version=TLSv1.2 cipher=RC4-SHA bits=128/128);\n\tMon, 05 Oct 2015 10:53:41 -0700 (PDT)"
        ],
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20130820;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=LRkOipJFv3u4rHC4iJcikTUyO6Ag8ccchwLUoK60rPs=;\n\tb=A4rZNLah74eS4KMCwqam9ayym7zLedTp56LM6bQN3ePtvVljWwWJWYzeseyXw5iJ0O\n\tfYxnm7isBNvwklrDRcENij6T4TsVDBvWLTEbasHXsV3v2y1QtPzRZgVU2XeIgQTR6ePD\n\twQspYb5t33RlYRqHXdJnInOtknOiJC6F9bNBJM8AzSw01B3wNzLiVak7/RUnXG5jjYOK\n\tP1UM295jatvIq1bwYQE42My0lyLuRnNC9a2/3GkQOtdGX7XuSLOsR0bLrqSdcflWpx2W\n\trR+NlC/YV+dTkPFSmFPBkmztUHtVIf8A9ZceAfjviD/c1zL1t/Ll875QwioqqzFSjsc3\n\td7aQ==",
        "X-Gm-Message-State": "ALoCoQmYbrH9+8r5IzlF/RtAyb264rz1LVHieggwxzC7dNyqv3wiNPXSUzLmkZdp7xg4Az6OMzie",
        "X-Received": "by 10.180.93.168 with SMTP id cv8mr13571427wib.54.1444067622057; \n\tMon, 05 Oct 2015 10:53:42 -0700 (PDT)",
        "From": "Adrien Mazarguil <adrien.mazarguil@6wind.com>",
        "To": "dev@dpdk.org",
        "Date": "Mon,  5 Oct 2015 19:52:59 +0200",
        "Message-Id": "<1444067589-29513-4-git-send-email-adrien.mazarguil@6wind.com>",
        "X-Mailer": "git-send-email 2.1.0",
        "In-Reply-To": "<1444067589-29513-1-git-send-email-adrien.mazarguil@6wind.com>",
        "References": "<1444067589-29513-1-git-send-email-adrien.mazarguil@6wind.com>",
        "Subject": "[dpdk-dev] [PATCH 03/13] mlx5: add MAC handling",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This commit adds support for MAC flow steering rules mandatory for the RX\npath as well as the related callbacks to add/remove MAC addresses.\n\nSigned-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>\nSigned-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>\nSigned-off-by: Didier Pallard <didier.pallard@6wind.com>\n---\n drivers/net/mlx5/mlx5.c     |   4 +-\n drivers/net/mlx5/mlx5.h     |   5 +\n drivers/net/mlx5/mlx5_mac.c | 347 ++++++++++++++++++++++++++++++++++++++++++++\n drivers/net/mlx5/mlx5_rxq.c |  10 ++\n 4 files changed, 365 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 31ce5ec..fb306d4 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -134,6 +134,8 @@ static const struct eth_dev_ops mlx5_dev_ops = {\n \t.tx_queue_setup = mlx5_tx_queue_setup,\n \t.rx_queue_release = mlx5_rx_queue_release,\n \t.tx_queue_release = mlx5_tx_queue_release,\n+\t.mac_addr_remove = mlx5_mac_addr_remove,\n+\t.mac_addr_add = mlx5_mac_addr_add,\n };\n \n static struct {\n@@ -390,7 +392,7 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)\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-\t\tclaim_zero(priv_mac_addr_add(priv, 1,\n+\t\tclaim_zero(priv_mac_addr_add(priv, (RTE_DIM(priv->mac) - 1),\n \t\t\t\t\t     &(const uint8_t [ETHER_ADDR_LEN])\n \t\t\t\t\t     { \"\\xff\\xff\\xff\\xff\\xff\\xff\" }));\n #ifndef NDEBUG\ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex 7e60e70..3e0c11e 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -173,7 +173,12 @@ int mlx5_ibv_device_to_pci_addr(const struct ibv_device *,\n /* mlx5_mac.c */\n \n int priv_get_mac(struct priv *, uint8_t (*)[ETHER_ADDR_LEN]);\n+void rxq_mac_addrs_del(struct rxq *);\n+void mlx5_mac_addr_remove(struct rte_eth_dev *, uint32_t);\n+int rxq_mac_addrs_add(struct rxq *);\n int priv_mac_addr_add(struct priv *, unsigned int,\n \t\t      const uint8_t (*)[ETHER_ADDR_LEN]);\n+void mlx5_mac_addr_add(struct rte_eth_dev *, struct ether_addr *, uint32_t,\n+\t\t       uint32_t);\n \n #endif /* RTE_PMD_MLX5_H_ */\ndiff --git a/drivers/net/mlx5/mlx5_mac.c b/drivers/net/mlx5/mlx5_mac.c\nindex f7e1cf6..f01faf0 100644\n--- a/drivers/net/mlx5/mlx5_mac.c\n+++ b/drivers/net/mlx5/mlx5_mac.c\n@@ -65,6 +65,8 @@\n \n #include \"mlx5.h\"\n #include \"mlx5_utils.h\"\n+#include \"mlx5_rxtx.h\"\n+#include \"mlx5_defs.h\"\n \n /**\n  * Get MAC address by querying netdevice.\n@@ -89,8 +91,86 @@ priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN])\n }\n \n /**\n+ * Delete flow steering rule.\n+ *\n+ * @param rxq\n+ *   Pointer to RX queue structure.\n+ * @param mac_index\n+ *   MAC address index.\n+ * @param vlan_index\n+ *   VLAN index.\n+ */\n+static void\n+rxq_del_flow(struct rxq *rxq, unsigned int mac_index, unsigned int vlan_index)\n+{\n+#ifndef NDEBUG\n+\tstruct priv *priv = rxq->priv;\n+\tconst uint8_t (*mac)[ETHER_ADDR_LEN] =\n+\t\t(const uint8_t (*)[ETHER_ADDR_LEN])\n+\t\tpriv->mac[mac_index].addr_bytes;\n+#endif\n+\tassert(rxq->mac_flow[mac_index][vlan_index] != NULL);\n+\tDEBUG(\"%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u\"\n+\t      \" (VLAN ID %\" PRIu16 \")\",\n+\t      (void *)rxq,\n+\t      (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],\n+\t      mac_index, priv->vlan_filter[vlan_index].id);\n+\tclaim_zero(ibv_destroy_flow(rxq->mac_flow[mac_index][vlan_index]));\n+\trxq->mac_flow[mac_index][vlan_index] = NULL;\n+}\n+\n+/**\n+ * Unregister a MAC address from a RX queue.\n+ *\n+ * @param rxq\n+ *   Pointer to RX queue structure.\n+ * @param mac_index\n+ *   MAC address index.\n+ */\n+static void\n+rxq_mac_addr_del(struct rxq *rxq, unsigned int mac_index)\n+{\n+\tstruct priv *priv = rxq->priv;\n+\tunsigned int i;\n+\tunsigned int vlans = 0;\n+\n+\tassert(mac_index < RTE_DIM(priv->mac));\n+\tif (!BITFIELD_ISSET(rxq->mac_configured, mac_index))\n+\t\treturn;\n+\tfor (i = 0; (i != RTE_DIM(priv->vlan_filter)); ++i) {\n+\t\tif (!priv->vlan_filter[i].enabled)\n+\t\t\tcontinue;\n+\t\trxq_del_flow(rxq, mac_index, i);\n+\t\tvlans++;\n+\t}\n+\tif (!vlans) {\n+\t\trxq_del_flow(rxq, mac_index, 0);\n+\t}\n+\tBITFIELD_RESET(rxq->mac_configured, mac_index);\n+}\n+\n+/**\n+ * Unregister all MAC addresses from a RX queue.\n+ *\n+ * @param rxq\n+ *   Pointer to RX queue structure.\n+ */\n+void\n+rxq_mac_addrs_del(struct rxq *rxq)\n+{\n+\tstruct priv *priv = rxq->priv;\n+\tunsigned int i;\n+\n+\tfor (i = 0; (i != RTE_DIM(priv->mac)); ++i)\n+\t\trxq_mac_addr_del(rxq, i);\n+}\n+\n+/**\n  * Unregister a MAC address.\n  *\n+ * In RSS mode, the MAC address is unregistered from the parent queue,\n+ * otherwise it is unregistered from each queue directly.\n+ *\n  * @param priv\n  *   Pointer to private structure.\n  * @param mac_index\n@@ -99,15 +179,217 @@ priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN])\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+\tif (priv->rss) {\n+\t\trxq_mac_addr_del(&priv->rxq_parent, mac_index);\n+\t\tgoto end;\n+\t}\n+\tfor (i = 0; (i != priv->dev->data->nb_rx_queues); ++i)\n+\t\trxq_mac_addr_del((*priv->rxqs)[i], mac_index);\n+end:\n \tBITFIELD_RESET(priv->mac_configured, mac_index);\n }\n \n /**\n+ * DPDK callback to remove a MAC address.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device structure.\n+ * @param index\n+ *   MAC address index.\n+ */\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+\tpriv_lock(priv);\n+\tDEBUG(\"%p: removing MAC address from index %\" PRIu32,\n+\t      (void *)dev, index);\n+\t/* Last array entry is reserved for broadcast. */\n+\tif (index >= (RTE_DIM(priv->mac) - 1))\n+\t\tgoto end;\n+\tpriv_mac_addr_del(priv, index);\n+end:\n+\tpriv_unlock(priv);\n+}\n+\n+/**\n+ * Add single flow steering rule.\n+ *\n+ * @param rxq\n+ *   Pointer to RX queue structure.\n+ * @param mac_index\n+ *   MAC address index to register.\n+ * @param vlan_index\n+ *   VLAN index. Use -1 for a flow without VLAN.\n+ *\n+ * @return\n+ *   0 on success, errno value on failure.\n+ */\n+static int\n+rxq_add_flow(struct rxq *rxq, unsigned int mac_index, unsigned int vlan_index)\n+{\n+\tstruct ibv_flow *flow;\n+\tstruct priv *priv = 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+\n+\t/* Allocate flow specification on the stack. */\n+\tstruct __attribute__((packed)) {\n+\t\tstruct ibv_flow_attr attr;\n+\t\tstruct ibv_flow_spec_eth spec;\n+\t} data;\n+\tstruct ibv_flow_attr *attr = &data.attr;\n+\tstruct ibv_flow_spec_eth *spec = &data.spec;\n+\n+\tassert(mac_index < RTE_DIM(priv->mac));\n+\tassert((vlan_index < RTE_DIM(priv->vlan_filter)) || (vlan_index == -1u));\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+\t*attr = (struct ibv_flow_attr){\n+\t\t.type = IBV_FLOW_ATTR_NORMAL,\n+\t\t.num_of_specs = 1,\n+\t\t.port = priv->port,\n+\t\t.flags = 0\n+\t};\n+\t*spec = (struct ibv_flow_spec_eth){\n+\t\t.type = IBV_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_index != -1u) ?\n+\t\t\t\t     htons(priv->vlan_filter[vlan_index].id) :\n+\t\t\t\t     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_index != -1u) ? 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 %s %\" PRIu16 \")\",\n+\t      (void *)rxq,\n+\t      (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],\n+\t      mac_index,\n+\t      ((vlan_index != -1u) ? \"ID\" : \"index\"),\n+\t      ((vlan_index != -1u) ? priv->vlan_filter[vlan_index].id : -1u));\n+\t/* Create related flow. */\n+\terrno = 0;\n+\tflow = ibv_create_flow(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 *)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+\tif (vlan_index == -1u)\n+\t\tvlan_index = 0;\n+\tassert(rxq->mac_flow[mac_index][vlan_index] == NULL);\n+\trxq->mac_flow[mac_index][vlan_index] = flow;\n+\treturn 0;\n+}\n+\n+/**\n+ * Register a MAC address in a RX queue.\n+ *\n+ * @param rxq\n+ *   Pointer to 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+rxq_mac_addr_add(struct rxq *rxq, unsigned int mac_index)\n+{\n+\tstruct priv *priv = rxq->priv;\n+\tunsigned int i;\n+\tunsigned int vlans = 0;\n+\tint ret;\n+\n+\tassert(mac_index < RTE_DIM(priv->mac));\n+\tif (BITFIELD_ISSET(rxq->mac_configured, mac_index))\n+\t\trxq_mac_addr_del(rxq, mac_index);\n+\t/* Fill VLAN specifications. */\n+\tfor (i = 0; (i != RTE_DIM(priv->vlan_filter)); ++i) {\n+\t\tif (!priv->vlan_filter[i].enabled)\n+\t\t\tcontinue;\n+\t\t/* Create related flow. */\n+\t\tret = rxq_add_flow(rxq, mac_index, i);\n+\t\tif (!ret) {\n+\t\t\tvlans++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\t/* Failure, rollback. */\n+\t\twhile (i != 0)\n+\t\t\tif (priv->vlan_filter[--i].enabled)\n+\t\t\t\trxq_del_flow(rxq, mac_index, i);\n+\t\tassert(ret > 0);\n+\t\treturn ret;\n+\t}\n+\t/* In case there is no VLAN filter. */\n+\tif (!vlans) {\n+\t\tret = rxq_add_flow(rxq, mac_index, -1);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\tBITFIELD_SET(rxq->mac_configured, mac_index);\n+\treturn 0;\n+}\n+\n+/**\n+ * Register all MAC addresses in a RX queue.\n+ *\n+ * @param rxq\n+ *   Pointer to RX queue structure.\n+ *\n+ * @return\n+ *   0 on success, errno value on failure.\n+ */\n+int\n+rxq_mac_addrs_add(struct rxq *rxq)\n+{\n+\tstruct priv *priv = rxq->priv;\n+\tunsigned int i;\n+\tint ret;\n+\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 = rxq_mac_addr_add(rxq, i);\n+\t\tif (!ret)\n+\t\t\tcontinue;\n+\t\t/* Failure, rollback. */\n+\t\twhile (i != 0)\n+\t\t\trxq_mac_addr_del(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+ * In RSS mode, the MAC address is registered in the parent queue,\n+ * otherwise it is registered in each queue directly.\n+ *\n  * @param priv\n  *   Pointer to private structure.\n  * @param mac_index\n@@ -123,6 +405,7 @@ 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@@ -145,6 +428,70 @@ priv_mac_addr_add(struct priv *priv, unsigned int mac_index,\n \t\t\t(*mac)[3], (*mac)[4], (*mac)[5]\n \t\t}\n \t};\n+\t/* If device isn't started, this is all we need to do. */\n+\tif (!priv->started) {\n+#ifndef NDEBUG\n+\t\t/* Verify that all queues have this index disabled. */\n+\t\tfor (i = 0; (i != priv->rxqs_n); ++i) {\n+\t\t\tif ((*priv->rxqs)[i] == NULL)\n+\t\t\t\tcontinue;\n+\t\t\tassert(!BITFIELD_ISSET\n+\t\t\t       ((*priv->rxqs)[i]->mac_configured, mac_index));\n+\t\t}\n+#endif\n+\t\tgoto end;\n+\t}\n+\tif (priv->rss) {\n+\t\tret = rxq_mac_addr_add(&priv->rxq_parent, mac_index);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t\tgoto end;\n+\t}\n+\tfor (i = 0; (i != priv->rxqs_n); ++i) {\n+\t\tif ((*priv->rxqs)[i] == NULL)\n+\t\t\tcontinue;\n+\t\tret = rxq_mac_addr_add((*priv->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\tif ((*priv->rxqs)[(--i)] != NULL)\n+\t\t\t\trxq_mac_addr_del((*priv->rxqs)[i], 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+ * DPDK callback to add a MAC address.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device structure.\n+ * @param mac_addr\n+ *   MAC address to register.\n+ * @param index\n+ *   MAC address index.\n+ * @param vmdq\n+ *   VMDq pool index to associate address with (ignored).\n+ */\n+void\n+mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,\n+\t\t  uint32_t index, uint32_t vmdq)\n+{\n+\tstruct priv *priv = dev->data->dev_private;\n+\n+\t(void)vmdq;\n+\tpriv_lock(priv);\n+\tDEBUG(\"%p: adding MAC address at index %\" PRIu32,\n+\t      (void *)dev, index);\n+\t/* Last array entry is reserved for broadcast. */\n+\tif (index >= (RTE_DIM(priv->mac) - 1))\n+\t\tgoto end;\n+\tpriv_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+}\ndiff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c\nindex 01cc649..8450fe3 100644\n--- a/drivers/net/mlx5/mlx5_rxq.c\n+++ b/drivers/net/mlx5/mlx5_rxq.c\n@@ -248,6 +248,7 @@ rxq_cleanup(struct rxq *rxq)\n \t\t\t\t\t\t&params));\n \t}\n \tif (rxq->qp != NULL) {\n+\t\trxq_mac_addrs_del(rxq);\n \t\tclaim_zero(ibv_destroy_qp(rxq->qp));\n \t}\n \tif (rxq->cq != NULL)\n@@ -515,6 +516,15 @@ skip_mr:\n \t\t      (void *)dev, strerror(ret));\n \t\tgoto error;\n \t}\n+\tif ((parent) || (!priv->rss))  {\n+\t\t/* Configure MAC and broadcast addresses. */\n+\t\tret = rxq_mac_addrs_add(&tmpl);\n+\t\tif (ret) {\n+\t\t\tERROR(\"%p: QP flow attachment failed: %s\",\n+\t\t\t      (void *)dev, strerror(ret));\n+\t\t\tgoto error;\n+\t\t}\n+\t}\n \t/* Allocate descriptors for RX queues, except for the RSS parent. */\n \tif (parent)\n \t\tgoto skip_alloc;\n",
    "prefixes": [
        "dpdk-dev",
        "03/13"
    ]
}