get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 29970,
    "url": "https://patches.dpdk.org/api/patches/29970/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/44504c8115645bb22a95b70d9a57eb1f32890d6c.1507560012.git.nelio.laranjeiro@6wind.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<44504c8115645bb22a95b70d9a57eb1f32890d6c.1507560012.git.nelio.laranjeiro@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/44504c8115645bb22a95b70d9a57eb1f32890d6c.1507560012.git.nelio.laranjeiro@6wind.com",
    "date": "2017-10-09T14:44:51",
    "name": "[dpdk-dev,v3,15/30] net/mlx5: add Hash Rx queue object",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "2e87c8d03c3dfb97a3e8b80cba6252466f546e8c",
    "submitter": {
        "id": 243,
        "url": "https://patches.dpdk.org/api/people/243/?format=api",
        "name": "Nélio Laranjeiro",
        "email": "nelio.laranjeiro@6wind.com"
    },
    "delegate": {
        "id": 319,
        "url": "https://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/44504c8115645bb22a95b70d9a57eb1f32890d6c.1507560012.git.nelio.laranjeiro@6wind.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/29970/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/29970/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 51E371B250;\n\tMon,  9 Oct 2017 16:45:51 +0200 (CEST)",
            "from mail-wm0-f45.google.com (mail-wm0-f45.google.com\n\t[74.125.82.45]) by dpdk.org (Postfix) with ESMTP id 0DFD91B1ED\n\tfor <dev@dpdk.org>; Mon,  9 Oct 2017 16:45:39 +0200 (CEST)",
            "by mail-wm0-f45.google.com with SMTP id i124so24147262wmf.3\n\tfor <dev@dpdk.org>; Mon, 09 Oct 2017 07:45:39 -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\tx15sm6791495wma.32.2017.10.09.07.45.37\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tMon, 09 Oct 2017 07:45:37 -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=H/toxwSoByvtokW3NCtt0KVt3kUx9CSKCanRrll8NBA=;\n\tb=xnsWs9ubkQtK4iE8yZOGXfc++HjkN7XBbh1YjSMrtnHQHOJRaI69eZWgTRiMtiD4bP\n\tzIUF3Sh8V1eTq5zp2S52ihip/2vMZGotob9Fcc4Jy4RmuBA2RA/kVVfkrlIIxAkb6WyI\n\tw1wdURQ/lqRwgkPBBRzQzU/vgwFuCn5ics6Immo3HIwPyWNWt4GV/GfbzClWt2fwcJAP\n\t1CFxUF+CJGoxf/zKJt6UG1B4+ttuEEVvMnnubWqHWXPtuxdqztNSD5QyuRw3wyu3f9JI\n\tkzYDi/rmqPuEgF3PG+qhtxtoe+TJyc0FkhSgGYa//Q+3DSWIxk5l0FS6zGSFZ03B7WaF\n\tsBGQ==",
        "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=H/toxwSoByvtokW3NCtt0KVt3kUx9CSKCanRrll8NBA=;\n\tb=uDizoRSxIInfOU2EPaRYQujMTyvRPi2Df9pmBXCnOutJr24vojU07g/KFDxiM6xbgi\n\trZtssgo0CK5PtMe9aD5IQPIFN3NaBuYkXcPdKxZujCXFlEID7HM/ORIJXmdUDCRjvDsn\n\twZpYWeRQjhzL2vI7KxX6B+WvozLVvXGF06PCFg9csHjj/RUnj4eHHRjtYvL4MHWbCyRC\n\tVkSHVFYmyHWUFooEkchzryA+3l8ktUMWM1Go4wE2d+ll5yL//UuXam+YCTGq6KRTQYLg\n\t1IYUeM4AsJ/PYDXna90D9NfevqboQ8beS3nFBSfIH+gQZ2gGiQrkcwpkmzPx8tlMMJKK\n\tVn6Q==",
        "X-Gm-Message-State": "AMCzsaUDWJUCejh9AtSKlozdC1SD1+k+W021OHtISQx2YyZAHELJumjz\n\tl1upX3RWGIlZjrm0R1Q/nbw15LnwYQ==",
        "X-Google-Smtp-Source": "AOwi7QBl76ZdSvmbVxwp4ftIxLPwwmdU6zpBZcK/LkaqaDieaZ3Sl9O76teHqJbaEC3FiqPoYbvhJA==",
        "X-Received": "by 10.28.144.206 with SMTP id s197mr9851188wmd.142.1507560338184;\n\tMon, 09 Oct 2017 07:45:38 -0700 (PDT)",
        "From": "Nelio Laranjeiro <nelio.laranjeiro@6wind.com>",
        "To": "dev@dpdk.org",
        "Cc": "adrien.mazarguil@6wind.com, yskoh@mellanox.com, ferruh.yigit@intel.com",
        "Date": "Mon,  9 Oct 2017 16:44:51 +0200",
        "Message-Id": "<44504c8115645bb22a95b70d9a57eb1f32890d6c.1507560012.git.nelio.laranjeiro@6wind.com>",
        "X-Mailer": "git-send-email 2.1.4",
        "In-Reply-To": [
            "<cover.1507560012.git.nelio.laranjeiro@6wind.com>",
            "<cover.1507560012.git.nelio.laranjeiro@6wind.com>"
        ],
        "References": [
            "<cover.1507560012.git.nelio.laranjeiro@6wind.com>",
            "<cover.1501681927.git.nelio.laranjeiro@6wind.com>\n\t<cover.1507560012.git.nelio.laranjeiro@6wind.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH v3 15/30] net/mlx5: add Hash Rx queue object",
        "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": "Hash Rx queue is an high level queue providing the RSS hash algorithm, key\nand indirection table to spread the packets.  Those objects can be easily\nshared between several Verbs flows.  This commit bring this capability to\nthe PMD.\n\nSigned-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>\nAcked-by: Yongseok Koh <yskoh@mellanox.com>\n---\n drivers/net/mlx5/mlx5.c      |   3 +\n drivers/net/mlx5/mlx5.h      |   3 +-\n drivers/net/mlx5/mlx5_flow.c | 228 ++++++++++++++++++++++++-------------------\n drivers/net/mlx5/mlx5_rxq.c  | 165 +++++++++++++++++++++++++++++++\n drivers/net/mlx5/mlx5_rxtx.h |  17 ++++\n 5 files changed, 312 insertions(+), 104 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 46b4067..fd8138b 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -235,6 +235,9 @@ mlx5_dev_close(struct rte_eth_dev *dev)\n \tif (priv->reta_idx != NULL)\n \t\trte_free(priv->reta_idx);\n \tpriv_socket_uninit(priv);\n+\tret = mlx5_priv_hrxq_ibv_verify(priv);\n+\tif (ret)\n+\t\tWARN(\"%p: some Hash Rx queue still remain\", (void *)priv);\n \tret = mlx5_priv_ind_table_ibv_verify(priv);\n \tif (ret)\n \t\tWARN(\"%p: some Indirection table still remain\", (void *)priv);\ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex ab17ce6..77413c9 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -144,11 +144,12 @@ struct priv {\n \tstruct rte_intr_handle intr_handle; /* Interrupt handler. */\n \tunsigned int (*reta_idx)[]; /* RETA index table. */\n \tunsigned int reta_idx_n; /* RETA index size. */\n-\tstruct rte_flow_drop *flow_drop_queue; /* Flow drop queue. */\n+\tstruct mlx5_hrxq_drop *flow_drop_queue; /* Flow drop queue. */\n \tTAILQ_HEAD(mlx5_flows, rte_flow) flows; /* RTE Flow rules. */\n \tLIST_HEAD(mr, mlx5_mr) mr; /* Memory region. */\n \tLIST_HEAD(rxq, mlx5_rxq_ctrl) rxqsctrl; /* DPDK Rx queues. */\n \tLIST_HEAD(rxqibv, mlx5_rxq_ibv) rxqsibv; /* Verbs Rx queues. */\n+\tLIST_HEAD(hrxq, mlx5_hrxq) hrxqs; /* Verbs Hash Rx queues. */\n \tLIST_HEAD(txq, mlx5_txq_ctrl) txqsctrl; /* DPDK Tx queues. */\n \tLIST_HEAD(txqibv, mlx5_txq_ibv) txqsibv; /* Verbs Tx queues. */\n \t/* Verbs Indirection tables. */\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex dc9adeb..4948882 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -87,17 +87,37 @@ mlx5_flow_create_vxlan(const struct rte_flow_item *item,\n \t\t       const void *default_mask,\n \t\t       void *data);\n \n-struct rte_flow {\n-\tTAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */\n-\tstruct ibv_flow_attr *ibv_attr; /**< Pointer to Verbs attributes. */\n-\tstruct mlx5_ind_table_ibv *ind_table; /**< Indirection table. */\n+/** Structure for Drop queue. */\n+struct mlx5_hrxq_drop {\n+\tstruct ibv_rwq_ind_table *ind_table; /**< Indirection table. */\n \tstruct ibv_qp *qp; /**< Verbs queue pair. */\n-\tstruct ibv_flow *ibv_flow; /**< Verbs flow. */\n \tstruct ibv_wq *wq; /**< Verbs work queue. */\n \tstruct ibv_cq *cq; /**< Verbs completion queue. */\n+};\n+\n+/* Flows structures. */\n+struct mlx5_flow {\n+\tuint64_t hash_fields; /**< Fields that participate in the hash. */\n+\tstruct mlx5_hrxq *hrxq; /**< Hash Rx queues. */\n+};\n+\n+/* Drop flows structures. */\n+struct mlx5_flow_drop {\n+\tstruct mlx5_hrxq_drop hrxq; /**< Drop hash Rx queue. */\n+};\n+\n+struct rte_flow {\n+\tTAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */\n \tuint32_t mark:1; /**< Set if the flow is marked. */\n \tuint32_t drop:1; /**< Drop queue. */\n-\tuint64_t hash_fields; /**< Fields that participate in the hash. */\n+\tstruct ibv_flow_attr *ibv_attr; /**< Pointer to Verbs attributes. */\n+\tstruct ibv_flow *ibv_flow; /**< Verbs flow. */\n+\tuint16_t queues_n; /**< Number of entries in queue[]. */\n+\tuint16_t (*queues)[]; /**< Queues indexes to use. */\n+\tunion {\n+\t\tstruct mlx5_flow frxq; /**< Flow with Rx queue. */\n+\t\tstruct mlx5_flow_drop drxq; /**< Flow with drop Rx queue. */\n+\t};\n };\n \n /** Static initializer for items. */\n@@ -288,14 +308,6 @@ struct mlx5_flow_parse {\n \tstruct mlx5_flow_action actions; /**< Parsed action result. */\n };\n \n-/** Structure for Drop queue. */\n-struct rte_flow_drop {\n-\tstruct ibv_rwq_ind_table *ind_table; /**< Indirection table. */\n-\tstruct ibv_qp *qp; /**< Verbs queue pair. */\n-\tstruct ibv_wq *wq; /**< Verbs work queue. */\n-\tstruct ibv_cq *cq; /**< Verbs completion queue. */\n-};\n-\n static const struct rte_flow_ops mlx5_flow_ops = {\n \t.validate = mlx5_flow_validate,\n \t.create = mlx5_flow_create,\n@@ -1052,8 +1064,8 @@ priv_flow_create_action_queue_drop(struct priv *priv,\n \trte_flow->ibv_attr = flow->ibv_attr;\n \tif (!priv->dev->data->dev_started)\n \t\treturn rte_flow;\n-\trte_flow->qp = priv->flow_drop_queue->qp;\n-\trte_flow->ibv_flow = ibv_create_flow(rte_flow->qp,\n+\trte_flow->drxq.hrxq.qp = priv->flow_drop_queue->qp;\n+\trte_flow->ibv_flow = ibv_create_flow(rte_flow->drxq.hrxq.qp,\n \t\t\t\t\t     rte_flow->ibv_attr);\n \tif (!rte_flow->ibv_flow) {\n \t\trte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,\n@@ -1091,62 +1103,52 @@ priv_flow_create_action_queue(struct priv *priv,\n \tassert(priv->pd);\n \tassert(priv->ctx);\n \tassert(!flow->actions.drop);\n-\trte_flow = rte_calloc(__func__, 1, sizeof(*rte_flow), 0);\n+\trte_flow =\n+\t\trte_calloc(__func__, 1,\n+\t\t\t   sizeof(*flow) +\n+\t\t\t   flow->actions.queues_n * sizeof(uint16_t),\n+\t\t\t   0);\n \tif (!rte_flow) {\n \t\trte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,\n \t\t\t\t   NULL, \"cannot allocate flow memory\");\n \t\treturn NULL;\n \t}\n-\tfor (i = 0; i != flow->actions.queues_n; ++i) {\n-\t\tstruct mlx5_rxq_data *q =\n-\t\t\t(*priv->rxqs)[flow->actions.queues[i]];\n-\n-\t\tq->mark |= flow->actions.mark;\n-\t}\n \trte_flow->mark = flow->actions.mark;\n \trte_flow->ibv_attr = flow->ibv_attr;\n-\trte_flow->hash_fields = flow->hash_fields;\n-\trte_flow->ind_table =\n-\t\tmlx5_priv_ind_table_ibv_get(priv, flow->actions.queues,\n-\t\t\t\t\t    flow->actions.queues_n);\n-\tif (!rte_flow->ind_table) {\n-\t\trte_flow->ind_table =\n-\t\t\tmlx5_priv_ind_table_ibv_new(priv, flow->actions.queues,\n-\t\t\t\t\t\t    flow->actions.queues_n);\n-\t\tif (!rte_flow->ind_table) {\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,\n-\t\t\t\t\t   \"cannot allocate indirection table\");\n-\t\t\tgoto error;\n-\t\t}\n+\trte_flow->queues = (uint16_t (*)[])(rte_flow + 1);\n+\tmemcpy(rte_flow->queues, flow->actions.queues,\n+\t       flow->actions.queues_n * sizeof(uint16_t));\n+\trte_flow->queues_n = flow->actions.queues_n;\n+\trte_flow->frxq.hash_fields = flow->hash_fields;\n+\trte_flow->frxq.hrxq = mlx5_priv_hrxq_get(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 (*rte_flow->queues),\n+\t\t\t\t\t\t rte_flow->queues_n);\n+\tif (rte_flow->frxq.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->qp = ibv_create_qp_ex(\n-\t\tpriv->ctx,\n-\t\t&(struct ibv_qp_init_attr_ex){\n-\t\t\t.qp_type = IBV_QPT_RAW_PACKET,\n-\t\t\t.comp_mask =\n-\t\t\t\tIBV_QP_INIT_ATTR_PD |\n-\t\t\t\tIBV_QP_INIT_ATTR_IND_TABLE |\n-\t\t\t\tIBV_QP_INIT_ATTR_RX_HASH,\n-\t\t\t.rx_hash_conf = (struct ibv_rx_hash_conf){\n-\t\t\t\t.rx_hash_function =\n-\t\t\t\t\tIBV_RX_HASH_FUNC_TOEPLITZ,\n-\t\t\t\t.rx_hash_key_len = rss_hash_default_key_len,\n-\t\t\t\t.rx_hash_key = rss_hash_default_key,\n-\t\t\t\t.rx_hash_fields_mask = rte_flow->hash_fields,\n-\t\t\t},\n-\t\t\t.rwq_ind_tbl = rte_flow->ind_table->ind_table,\n-\t\t\t.pd = priv->pd\n-\t\t});\n-\tif (!rte_flow->qp) {\n+\trte_flow->frxq.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 (*rte_flow->queues),\n+\t\t\t\t\t\t rte_flow->queues_n);\n+\tif (!rte_flow->frxq.hrxq) {\n \t\trte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,\n-\t\t\t\t   NULL, \"cannot allocate QP\");\n+\t\t\t\t   NULL, \"cannot create hash rxq\");\n \t\tgoto error;\n \t}\n+\tfor (i = 0; i != flow->actions.queues_n; ++i) {\n+\t\tstruct mlx5_rxq_data *q =\n+\t\t\t(*priv->rxqs)[flow->actions.queues[i]];\n+\n+\t\tq->mark |= flow->actions.mark;\n+\t}\n \tif (!priv->dev->data->dev_started)\n \t\treturn rte_flow;\n-\trte_flow->ibv_flow = ibv_create_flow(rte_flow->qp,\n+\trte_flow->ibv_flow = ibv_create_flow(rte_flow->frxq.hrxq->qp,\n \t\t\t\t\t     rte_flow->ibv_attr);\n \tif (!rte_flow->ibv_flow) {\n \t\trte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,\n@@ -1156,10 +1158,8 @@ priv_flow_create_action_queue(struct priv *priv,\n \treturn rte_flow;\n error:\n \tassert(rte_flow);\n-\tif (rte_flow->qp)\n-\t\tibv_destroy_qp(rte_flow->qp);\n-\tif (rte_flow->ind_table)\n-\t\tmlx5_priv_ind_table_ibv_release(priv, rte_flow->ind_table);\n+\tif (rte_flow->frxq.hrxq)\n+\t\tmlx5_priv_hrxq_release(priv, rte_flow->frxq.hrxq);\n \trte_free(rte_flow);\n \treturn NULL;\n }\n@@ -1277,45 +1277,43 @@ priv_flow_destroy(struct priv *priv,\n \t\t  struct rte_flow *flow)\n {\n \tunsigned int i;\n+\tuint16_t *queues;\n+\tuint16_t queues_n;\n \n-\tTAILQ_REMOVE(&priv->flows, flow, next);\n-\tif (flow->ibv_flow)\n-\t\tclaim_zero(ibv_destroy_flow(flow->ibv_flow));\n-\tif (flow->drop)\n+\tif (flow->drop || !flow->mark)\n \t\tgoto free;\n-\tif (flow->qp)\n-\t\tclaim_zero(ibv_destroy_qp(flow->qp));\n-\tfor (i = 0; i != flow->ind_table->queues_n; ++i) {\n+\tqueues = flow->frxq.hrxq->ind_table->queues;\n+\tqueues_n = flow->frxq.hrxq->ind_table->queues_n;\n+\tfor (i = 0; i != queues_n; ++i) {\n \t\tstruct rte_flow *tmp;\n-\t\tstruct mlx5_rxq_data *rxq_data =\n-\t\t\t(*priv->rxqs)[flow->ind_table->queues[i]];\n+\t\tstruct mlx5_rxq_data *rxq_data = (*priv->rxqs)[queues[i]];\n+\t\tint mark = 0;\n \n \t\t/*\n \t\t * To remove the mark from the queue, the queue must not be\n \t\t * present in any other marked flow (RSS or not).\n \t\t */\n-\t\tif (flow->mark) {\n-\t\t\tint mark = 0;\n-\n-\t\t\tTAILQ_FOREACH(tmp, &priv->flows, next) {\n-\t\t\t\tunsigned int j;\n-\n-\t\t\t\tif (tmp->drop)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tif (!tmp->mark)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tfor (j = 0;\n-\t\t\t\t     (j != tmp->ind_table->queues_n) && !mark;\n-\t\t\t\t     j++)\n-\t\t\t\t\tif (tmp->ind_table->queues[j] ==\n-\t\t\t\t\t    flow->ind_table->queues[i])\n-\t\t\t\t\t\tmark = 1;\n-\t\t\t}\n-\t\t\trxq_data->mark = mark;\n+\t\tTAILQ_FOREACH(tmp, &priv->flows, next) {\n+\t\t\tunsigned int j;\n+\n+\t\t\tif (!tmp->mark)\n+\t\t\t\tcontinue;\n+\t\t\tfor (j = 0;\n+\t\t\t     (j != tmp->frxq.hrxq->ind_table->queues_n) &&\n+\t\t\t     !mark;\n+\t\t\t     j++)\n+\t\t\t\tif (tmp->frxq.hrxq->ind_table->queues[j] ==\n+\t\t\t\t    queues[i])\n+\t\t\t\t\tmark = 1;\n \t\t}\n+\t\trxq_data->mark = mark;\n \t}\n-\tmlx5_priv_ind_table_ibv_release(priv, flow->ind_table);\n free:\n+\tif (flow->ibv_flow)\n+\t\tclaim_zero(ibv_destroy_flow(flow->ibv_flow));\n+\tif (!flow->drop)\n+\t\tmlx5_priv_hrxq_release(priv, flow->frxq.hrxq);\n+\tTAILQ_REMOVE(&priv->flows, flow, next);\n \trte_free(flow->ibv_attr);\n \tDEBUG(\"Flow destroyed %p\", (void *)flow);\n \trte_free(flow);\n@@ -1389,7 +1387,7 @@ mlx5_flow_flush(struct rte_eth_dev *dev,\n static int\n priv_flow_create_drop_queue(struct priv *priv)\n {\n-\tstruct rte_flow_drop *fdq = NULL;\n+\tstruct mlx5_hrxq_drop *fdq = NULL;\n \n \tassert(priv->pd);\n \tassert(priv->ctx);\n@@ -1472,7 +1470,7 @@ priv_flow_create_drop_queue(struct priv *priv)\n static void\n priv_flow_delete_drop_queue(struct priv *priv)\n {\n-\tstruct rte_flow_drop *fdq = priv->flow_drop_queue;\n+\tstruct mlx5_hrxq_drop *fdq = priv->flow_drop_queue;\n \n \tif (!fdq)\n \t\treturn;\n@@ -1504,9 +1502,12 @@ priv_flow_stop(struct priv *priv)\n \tTAILQ_FOREACH_REVERSE(flow, &priv->flows, mlx5_flows, next) {\n \t\tclaim_zero(ibv_destroy_flow(flow->ibv_flow));\n \t\tflow->ibv_flow = NULL;\n+\t\tmlx5_priv_hrxq_release(priv, flow->frxq.hrxq);\n+\t\tflow->frxq.hrxq = NULL;\n \t\tif (flow->mark) {\n \t\t\tunsigned int n;\n-\t\t\tstruct mlx5_ind_table_ibv *ind_tbl = flow->ind_table;\n+\t\t\tstruct mlx5_ind_table_ibv *ind_tbl =\n+\t\t\t\tflow->frxq.hrxq->ind_table;\n \n \t\t\tfor (n = 0; n < ind_tbl->queues_n; ++n)\n \t\t\t\t(*priv->rxqs)[ind_tbl->queues[n]]->mark = 0;\n@@ -1535,13 +1536,31 @@ priv_flow_start(struct priv *priv)\n \tif (ret)\n \t\treturn -1;\n \tTAILQ_FOREACH(flow, &priv->flows, next) {\n-\t\tstruct ibv_qp *qp;\n-\n-\t\tif (flow->drop)\n-\t\t\tqp = priv->flow_drop_queue->qp;\n-\t\telse\n-\t\t\tqp = flow->qp;\n-\t\tflow->ibv_flow = ibv_create_flow(qp, flow->ibv_attr);\n+\t\tif (flow->frxq.hrxq)\n+\t\t\tgoto flow_create;\n+\t\tflow->frxq.hrxq =\n+\t\t\tmlx5_priv_hrxq_get(priv, rss_hash_default_key,\n+\t\t\t\t\t   rss_hash_default_key_len,\n+\t\t\t\t\t   flow->frxq.hash_fields,\n+\t\t\t\t\t   (*flow->queues),\n+\t\t\t\t\t   flow->queues_n);\n+\t\tif (flow->frxq.hrxq)\n+\t\t\tgoto flow_create;\n+\t\tflow->frxq.hrxq =\n+\t\t\tmlx5_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->frxq.hash_fields,\n+\t\t\t\t\t   (*flow->queues),\n+\t\t\t\t\t   flow->queues_n);\n+\t\tif (!flow->frxq.hrxq) {\n+\t\t\tDEBUG(\"Flow %p cannot be applied\",\n+\t\t\t      (void *)flow);\n+\t\t\trte_errno = EINVAL;\n+\t\t\treturn rte_errno;\n+\t\t}\n+flow_create:\n+\t\tflow->ibv_flow = ibv_create_flow(flow->frxq.hrxq->qp,\n+\t\t\t\t\t\t flow->ibv_attr);\n \t\tif (!flow->ibv_flow) {\n \t\t\tDEBUG(\"Flow %p cannot be applied\", (void *)flow);\n \t\t\trte_errno = EINVAL;\n@@ -1551,8 +1570,11 @@ priv_flow_start(struct priv *priv)\n \t\tif (flow->mark) {\n \t\t\tunsigned int n;\n \n-\t\t\tfor (n = 0; n < flow->ind_table->queues_n; ++n) {\n-\t\t\t\tuint16_t idx = flow->ind_table->queues[n];\n+\t\t\tfor (n = 0;\n+\t\t\t     n < flow->frxq.hrxq->ind_table->queues_n;\n+\t\t\t     ++n) {\n+\t\t\t\tuint16_t idx =\n+\t\t\t\t\tflow->frxq.hrxq->ind_table->queues[n];\n \t\t\t\t(*priv->rxqs)[idx]->mark = 1;\n \t\t\t}\n \t\t}\ndiff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c\nindex 4a53282..b240c16 100644\n--- a/drivers/net/mlx5/mlx5_rxq.c\n+++ b/drivers/net/mlx5/mlx5_rxq.c\n@@ -1775,3 +1775,168 @@ mlx5_priv_ind_table_ibv_verify(struct priv *priv)\n \t}\n \treturn ret;\n }\n+\n+/**\n+ * Create an Rx Hash queue.\n+ *\n+ * @param priv\n+ *   Pointer to private structure.\n+ * @param rss_key\n+ *   RSS key for the Rx hash queue.\n+ * @param rss_key_len\n+ *   RSS key length.\n+ * @param hash_fields\n+ *   Verbs protocol hash field to make the RSS on.\n+ * @param queues\n+ *   Queues entering in hash queue.\n+ * @param queues_n\n+ *   Number of queues.\n+ *\n+ * @return\n+ *   An hash Rx queue on success.\n+ */\n+struct mlx5_hrxq*\n+mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,\n+\t\t   uint64_t hash_fields, uint16_t queues[], uint16_t queues_n)\n+{\n+\tstruct mlx5_hrxq *hrxq;\n+\tstruct mlx5_ind_table_ibv *ind_tbl;\n+\tstruct ibv_qp *qp;\n+\n+\tind_tbl = mlx5_priv_ind_table_ibv_get(priv, queues, queues_n);\n+\tif (!ind_tbl)\n+\t\tind_tbl = mlx5_priv_ind_table_ibv_new(priv, queues, queues_n);\n+\tif (!ind_tbl)\n+\t\treturn NULL;\n+\tqp = ibv_create_qp_ex(\n+\t\tpriv->ctx,\n+\t\t&(struct ibv_qp_init_attr_ex){\n+\t\t\t.qp_type = IBV_QPT_RAW_PACKET,\n+\t\t\t.comp_mask =\n+\t\t\t\tIBV_QP_INIT_ATTR_PD |\n+\t\t\t\tIBV_QP_INIT_ATTR_IND_TABLE |\n+\t\t\t\tIBV_QP_INIT_ATTR_RX_HASH,\n+\t\t\t.rx_hash_conf = (struct ibv_rx_hash_conf){\n+\t\t\t\t.rx_hash_function = IBV_RX_HASH_FUNC_TOEPLITZ,\n+\t\t\t\t.rx_hash_key_len = rss_key_len,\n+\t\t\t\t.rx_hash_key = rss_key,\n+\t\t\t\t.rx_hash_fields_mask = hash_fields,\n+\t\t\t},\n+\t\t\t.rwq_ind_tbl = ind_tbl->ind_table,\n+\t\t\t.pd = priv->pd,\n+\t\t});\n+\tif (!qp)\n+\t\tgoto error;\n+\thrxq = rte_calloc(__func__, 1, sizeof(*hrxq) + rss_key_len, 0);\n+\tif (!hrxq)\n+\t\tgoto error;\n+\thrxq->ind_table = ind_tbl;\n+\thrxq->qp = qp;\n+\thrxq->rss_key_len = rss_key_len;\n+\thrxq->hash_fields = hash_fields;\n+\tmemcpy(hrxq->rss_key, rss_key, rss_key_len);\n+\trte_atomic32_inc(&hrxq->refcnt);\n+\tLIST_INSERT_HEAD(&priv->hrxqs, hrxq, next);\n+\tDEBUG(\"%p: Hash Rx queue %p: refcnt %d\", (void *)priv,\n+\t      (void *)hrxq, rte_atomic32_read(&hrxq->refcnt));\n+\treturn hrxq;\n+error:\n+\tmlx5_priv_ind_table_ibv_release(priv, ind_tbl);\n+\tif (qp)\n+\t\tclaim_zero(ibv_destroy_qp(qp));\n+\treturn NULL;\n+}\n+\n+/**\n+ * Get an Rx Hash queue.\n+ *\n+ * @param priv\n+ *   Pointer to private structure.\n+ * @param rss_conf\n+ *   RSS configuration for the Rx hash queue.\n+ * @param queues\n+ *   Queues entering in hash queue.\n+ * @param queues_n\n+ *   Number of queues.\n+ *\n+ * @return\n+ *   An hash Rx queue on success.\n+ */\n+struct mlx5_hrxq*\n+mlx5_priv_hrxq_get(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,\n+\t\t   uint64_t hash_fields, uint16_t queues[], uint16_t queues_n)\n+{\n+\tstruct mlx5_hrxq *hrxq;\n+\n+\tLIST_FOREACH(hrxq, &priv->hrxqs, next) {\n+\t\tstruct mlx5_ind_table_ibv *ind_tbl;\n+\n+\t\tif (hrxq->rss_key_len != rss_key_len)\n+\t\t\tcontinue;\n+\t\tif (memcmp(hrxq->rss_key, rss_key, rss_key_len))\n+\t\t\tcontinue;\n+\t\tif (hrxq->hash_fields != hash_fields)\n+\t\t\tcontinue;\n+\t\tind_tbl = mlx5_priv_ind_table_ibv_get(priv, queues, queues_n);\n+\t\tif (!ind_tbl)\n+\t\t\tcontinue;\n+\t\tif (ind_tbl != hrxq->ind_table) {\n+\t\t\tmlx5_priv_ind_table_ibv_release(priv, ind_tbl);\n+\t\t\tcontinue;\n+\t\t}\n+\t\trte_atomic32_inc(&hrxq->refcnt);\n+\t\tDEBUG(\"%p: Hash Rx queue %p: refcnt %d\", (void *)priv,\n+\t\t      (void *)hrxq, rte_atomic32_read(&hrxq->refcnt));\n+\t\treturn hrxq;\n+\t}\n+\treturn NULL;\n+}\n+\n+/**\n+ * Release the hash Rx queue.\n+ *\n+ * @param priv\n+ *   Pointer to private structure.\n+ * @param hrxq\n+ *   Pointer to Hash Rx queue to release.\n+ *\n+ * @return\n+ *   0 on success, errno value on failure.\n+ */\n+int\n+mlx5_priv_hrxq_release(struct priv *priv, struct mlx5_hrxq *hrxq)\n+{\n+\tDEBUG(\"%p: Hash Rx queue %p: refcnt %d\", (void *)priv,\n+\t      (void *)hrxq, rte_atomic32_read(&hrxq->refcnt));\n+\tif (rte_atomic32_dec_and_test(&hrxq->refcnt)) {\n+\t\tclaim_zero(ibv_destroy_qp(hrxq->qp));\n+\t\tmlx5_priv_ind_table_ibv_release(priv, hrxq->ind_table);\n+\t\tLIST_REMOVE(hrxq, next);\n+\t\trte_free(hrxq);\n+\t\treturn 0;\n+\t}\n+\tclaim_nonzero(mlx5_priv_ind_table_ibv_release(priv, hrxq->ind_table));\n+\treturn EBUSY;\n+}\n+\n+/**\n+ * Verify the Rx Queue list is empty\n+ *\n+ * @param priv\n+ *  Pointer to private structure.\n+ *\n+ * @return the number of object not released.\n+ */\n+int\n+mlx5_priv_hrxq_ibv_verify(struct priv *priv)\n+{\n+\tstruct mlx5_hrxq *hrxq;\n+\tint ret = 0;\n+\n+\tLIST_FOREACH(hrxq, &priv->hrxqs, next) {\n+\t\tDEBUG(\"%p: Verbs Hash Rx queue %p still referenced\",\n+\t\t      (void *)priv, (void *)hrxq);\n+\t\t++ret;\n+\t}\n+\treturn ret;\n+}\ndiff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h\nindex b7c75bf..bb0a65d 100644\n--- a/drivers/net/mlx5/mlx5_rxtx.h\n+++ b/drivers/net/mlx5/mlx5_rxtx.h\n@@ -165,6 +165,17 @@ struct mlx5_ind_table_ibv {\n \tuint16_t queues[]; /**< Queue list. */\n };\n \n+/* Hash Rx queue. */\n+struct mlx5_hrxq {\n+\tLIST_ENTRY(mlx5_hrxq) next; /* Pointer to the next element. */\n+\trte_atomic32_t refcnt; /* Reference counter. */\n+\tstruct mlx5_ind_table_ibv *ind_table; /* Indirection table. */\n+\tstruct ibv_qp *qp; /* Verbs queue pair. */\n+\tuint64_t hash_fields; /* Verbs Hash fields. */\n+\tuint8_t rss_key_len; /* Hash key length in bytes. */\n+\tuint8_t rss_key[]; /* Hash key. */\n+};\n+\n /* Hash RX queue types. */\n enum hash_rxq_type {\n \tHASH_RXQ_TCPV4,\n@@ -362,6 +373,12 @@ struct mlx5_ind_table_ibv *mlx5_priv_ind_table_ibv_get(struct priv *,\n \t\t\t\t\t\t       uint16_t);\n int mlx5_priv_ind_table_ibv_release(struct priv *, struct mlx5_ind_table_ibv *);\n int mlx5_priv_ind_table_ibv_verify(struct priv *);\n+struct mlx5_hrxq *mlx5_priv_hrxq_new(struct priv *, uint8_t *, uint8_t,\n+\t\t\t\t     uint64_t, uint16_t [], uint16_t);\n+struct mlx5_hrxq *mlx5_priv_hrxq_get(struct priv *, uint8_t *, uint8_t,\n+\t\t\t\t     uint64_t, uint16_t [], uint16_t);\n+int mlx5_priv_hrxq_release(struct priv *, struct mlx5_hrxq *);\n+int mlx5_priv_hrxq_ibv_verify(struct priv *);\n \n /* mlx5_txq.c */\n \n",
    "prefixes": [
        "dpdk-dev",
        "v3",
        "15/30"
    ]
}