All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/4] net/mlx: make rdma-core optional at run-time
@ 2018-01-24 23:24 Adrien Mazarguil
  2018-01-24 23:25 ` [PATCH v1 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
                   ` (4 more replies)
  0 siblings, 5 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-24 23:24 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

A problem encountered with Mellanox PMDs and frequently reported by DPDK
application developers and Linux distribution package maintainers is their
dependency on rdma-core components, namely libibverbs, libmlx4, and libmlx5.

For best performance in applications, DPDK is normally built as a collection
of library archives (.a files), whose external dependencies are inherited
through rte.app.mk during link.

When these PMDs are built-in, any binary DPDK package, whether DPDK itself
or derived applications, always have to pull rdma-core. This dependency is
not obvious and may be missed during the packaging of any intermediate layer
between DPDK itself and the end application.

While still required during compilation, this series trades this hard
dependency for an optional one, dynamically loaded at run-time through
dlopen().

It supersedes Shachar's previous work on the same topic [1] using a
different approach in order to preserve symbol versioning and address
the remaining issues.

[1] http://dpdk.org/ml/archives/dev/2017-December/085090.html

Adrien Mazarguil (3):
  net/mlx4: move rdma-core calls to separate file
  net/mlx4: spawn rdma-core dependency plug-in
  net/mlx5: spawn rdma-core dependency plug-in

Nelio Laranjeiro (1):
  net/mlx5: move rdma-core calls to separate file

 drivers/net/mlx4/Makefile        |  41 +++++
 drivers/net/mlx4/mlx4.c          | 115 ++++++++++--
 drivers/net/mlx4/mlx4_ethdev.c   |   3 +-
 drivers/net/mlx4/mlx4_flow.c     |  32 ++--
 drivers/net/mlx4/mlx4_glue.c     | 275 ++++++++++++++++++++++++++++
 drivers/net/mlx4/mlx4_glue.h     |  80 +++++++++
 drivers/net/mlx4/mlx4_intr.c     |  10 +-
 drivers/net/mlx4/mlx4_mr.c       |   7 +-
 drivers/net/mlx4/mlx4_rxq.c      |  53 +++---
 drivers/net/mlx4/mlx4_txq.c      |  17 +-
 drivers/net/mlx5/Makefile        |  41 +++++
 drivers/net/mlx5/mlx5.c          | 127 ++++++++++---
 drivers/net/mlx5/mlx5_ethdev.c   |   7 +-
 drivers/net/mlx5/mlx5_flow.c     |  71 ++++----
 drivers/net/mlx5/mlx5_glue.c     | 328 ++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h     | 100 +++++++++++
 drivers/net/mlx5/mlx5_mac.c      |   1 +
 drivers/net/mlx5/mlx5_mr.c       |   7 +-
 drivers/net/mlx5/mlx5_rss.c      |   1 +
 drivers/net/mlx5/mlx5_rxmode.c   |   1 +
 drivers/net/mlx5/mlx5_rxq.c      |  54 +++---
 drivers/net/mlx5/mlx5_rxtx.c     |   1 +
 drivers/net/mlx5/mlx5_rxtx.h     |   1 +
 drivers/net/mlx5/mlx5_rxtx_vec.c |   1 +
 drivers/net/mlx5/mlx5_txq.c      |  22 +--
 drivers/net/mlx5/mlx5_vlan.c     |   2 +-
 mk/rte.app.mk                    |   2 +-
 27 files changed, 1221 insertions(+), 179 deletions(-)
 create mode 100644 drivers/net/mlx4/mlx4_glue.c
 create mode 100644 drivers/net/mlx4/mlx4_glue.h
 create mode 100644 drivers/net/mlx5/mlx5_glue.c
 create mode 100644 drivers/net/mlx5/mlx5_glue.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v1 1/4] net/mlx4: move rdma-core calls to separate file
  2018-01-24 23:24 [PATCH v1 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
@ 2018-01-24 23:25 ` Adrien Mazarguil
  2018-01-24 23:58   ` Stephen Hemminger
  2018-01-24 23:25 ` [PATCH v1 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-24 23:25 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

This lays the groundwork for externalizing rdma-core as an optional
run-time dependency instead of a mandatory one.

No functional change.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 drivers/net/mlx4/Makefile      |   1 +
 drivers/net/mlx4/mlx4.c        |  35 ++---
 drivers/net/mlx4/mlx4_ethdev.c |   3 +-
 drivers/net/mlx4/mlx4_flow.c   |  32 +++--
 drivers/net/mlx4/mlx4_glue.c   | 275 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx4/mlx4_glue.h   |  80 +++++++++++
 drivers/net/mlx4/mlx4_intr.c   |  10 +-
 drivers/net/mlx4/mlx4_mr.c     |   7 +-
 drivers/net/mlx4/mlx4_rxq.c    |  53 +++----
 drivers/net/mlx4/mlx4_txq.c    |  17 +--
 10 files changed, 440 insertions(+), 73 deletions(-)

diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1f95e0df9..1d33c38ed 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -38,6 +38,7 @@ LIB = librte_pmd_mlx4.a
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_intr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxq.c
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 2a721e7e2..0fd9a999c 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -67,6 +67,7 @@
 #include <rte_mbuf.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -218,8 +219,8 @@ mlx4_dev_close(struct rte_eth_dev *dev)
 		mlx4_tx_queue_release(dev->data->tx_queues[i]);
 	if (priv->pd != NULL) {
 		assert(priv->ctx != NULL);
-		claim_zero(ibv_dealloc_pd(priv->pd));
-		claim_zero(ibv_close_device(priv->ctx));
+		claim_zero(mlx4_glue->dealloc_pd(priv->pd));
+		claim_zero(mlx4_glue->close_device(priv->ctx));
 	} else
 		assert(priv->ctx == NULL);
 	mlx4_intr_uninstall(priv);
@@ -436,7 +437,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 	(void)pci_drv;
 	assert(pci_drv == &mlx4_driver);
-	list = ibv_get_device_list(&i);
+	list = mlx4_glue->get_device_list(&i);
 	if (list == NULL) {
 		rte_errno = errno;
 		assert(rte_errno);
@@ -465,12 +466,12 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		      PCI_DEVICE_ID_MELLANOX_CONNECTX3VF);
 		INFO("PCI information matches, using device \"%s\" (VF: %s)",
 		     list[i]->name, (vf ? "true" : "false"));
-		attr_ctx = ibv_open_device(list[i]);
+		attr_ctx = mlx4_glue->open_device(list[i]);
 		err = errno;
 		break;
 	}
 	if (attr_ctx == NULL) {
-		ibv_free_device_list(list);
+		mlx4_glue->free_device_list(list);
 		switch (err) {
 		case 0:
 			rte_errno = ENODEV;
@@ -487,7 +488,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	}
 	ibv_dev = list[i];
 	DEBUG("device opened");
-	if (ibv_query_device(attr_ctx, &device_attr)) {
+	if (mlx4_glue->query_device(attr_ctx, &device_attr)) {
 		rte_errno = ENODEV;
 		goto error;
 	}
@@ -502,7 +503,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	if (!conf.ports.enabled)
 		conf.ports.enabled = conf.ports.present;
 	/* Retrieve extended device attributes. */
-	if (ibv_query_device_ex(attr_ctx, NULL, &device_attr_ex)) {
+	if (mlx4_glue->query_device_ex(attr_ctx, NULL, &device_attr_ex)) {
 		rte_errno = ENODEV;
 		goto error;
 	}
@@ -520,13 +521,13 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		if (!(conf.ports.enabled & (1 << i)))
 			continue;
 		DEBUG("using port %u", port);
-		ctx = ibv_open_device(ibv_dev);
+		ctx = mlx4_glue->open_device(ibv_dev);
 		if (ctx == NULL) {
 			rte_errno = ENODEV;
 			goto port_error;
 		}
 		/* Check port status. */
-		err = ibv_query_port(ctx, port, &port_attr);
+		err = mlx4_glue->query_port(ctx, port, &port_attr);
 		if (err) {
 			rte_errno = err;
 			ERROR("port query failed: %s", strerror(rte_errno));
@@ -540,7 +541,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		}
 		if (port_attr.state != IBV_PORT_ACTIVE)
 			DEBUG("port %d is not active: \"%s\" (%d)",
-			      port, ibv_port_state_str(port_attr.state),
+			      port, mlx4_glue->port_state_str(port_attr.state),
 			      port_attr.state);
 		/* Make asynchronous FD non-blocking to handle interrupts. */
 		if (mlx4_fd_set_non_blocking(ctx->async_fd) < 0) {
@@ -549,7 +550,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			goto port_error;
 		}
 		/* Allocate protection domain. */
-		pd = ibv_alloc_pd(ctx);
+		pd = mlx4_glue->alloc_pd(ctx);
 		if (pd == NULL) {
 			rte_errno = ENOMEM;
 			ERROR("PD allocation failure");
@@ -628,7 +629,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			char name[RTE_ETH_NAME_MAX_LEN];
 
 			snprintf(name, sizeof(name), "%s port %u",
-				 ibv_get_device_name(ibv_dev), port);
+				 mlx4_glue->get_device_name(ibv_dev), port);
 			eth_dev = rte_eth_dev_allocate(name);
 		}
 		if (eth_dev == NULL) {
@@ -671,9 +672,9 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 port_error:
 		rte_free(priv);
 		if (pd)
-			claim_zero(ibv_dealloc_pd(pd));
+			claim_zero(mlx4_glue->dealloc_pd(pd));
 		if (ctx)
-			claim_zero(ibv_close_device(ctx));
+			claim_zero(mlx4_glue->close_device(ctx));
 		if (eth_dev)
 			rte_eth_dev_release_port(eth_dev);
 		break;
@@ -688,9 +689,9 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	 */
 error:
 	if (attr_ctx)
-		claim_zero(ibv_close_device(attr_ctx));
+		claim_zero(mlx4_glue->close_device(attr_ctx));
 	if (list)
-		ibv_free_device_list(list);
+		mlx4_glue->free_device_list(list);
 	assert(rte_errno >= 0);
 	return -rte_errno;
 }
@@ -743,7 +744,7 @@ rte_mlx4_pmd_init(void)
 	 * using this PMD, which is not supported in forked processes.
 	 */
 	setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
-	ibv_fork_init();
+	mlx4_glue->fork_init();
 	rte_pci_register(&mlx4_driver);
 }
 
diff --git a/drivers/net/mlx4/mlx4_ethdev.c b/drivers/net/mlx4/mlx4_ethdev.c
index ca5fadc72..d1d940dc7 100644
--- a/drivers/net/mlx4/mlx4_ethdev.c
+++ b/drivers/net/mlx4/mlx4_ethdev.c
@@ -70,6 +70,7 @@
 
 #include "mlx4.h"
 #include "mlx4_flow.h"
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -1068,7 +1069,7 @@ mlx4_is_removed(struct rte_eth_dev *dev)
 	struct ibv_device_attr device_attr;
 	struct priv *priv = dev->data->dev_private;
 
-	if (ibv_query_device(priv->ctx, &device_attr) == EIO)
+	if (mlx4_glue->query_device(priv->ctx, &device_attr) == EIO)
 		return 1;
 	return 0;
 }
diff --git a/drivers/net/mlx4/mlx4_flow.c b/drivers/net/mlx4/mlx4_flow.c
index fb84060db..7f1f7e852 100644
--- a/drivers/net/mlx4/mlx4_flow.c
+++ b/drivers/net/mlx4/mlx4_flow.c
@@ -65,6 +65,7 @@
 
 /* PMD headers. */
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -922,24 +923,25 @@ mlx4_drop_get(struct priv *priv)
 		.priv = priv,
 		.refcnt = 1,
 	};
-	drop->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+	drop->cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 	if (!drop->cq)
 		goto error;
-	drop->qp = ibv_create_qp(priv->pd,
-				 &(struct ibv_qp_init_attr){
-					.send_cq = drop->cq,
-					.recv_cq = drop->cq,
-					.qp_type = IBV_QPT_RAW_PACKET,
-				 });
+	drop->qp = mlx4_glue->create_qp
+		(priv->pd,
+		 &(struct ibv_qp_init_attr){
+			.send_cq = drop->cq,
+			.recv_cq = drop->cq,
+			.qp_type = IBV_QPT_RAW_PACKET,
+		 });
 	if (!drop->qp)
 		goto error;
 	priv->drop = drop;
 	return drop;
 error:
 	if (drop->qp)
-		claim_zero(ibv_destroy_qp(drop->qp));
+		claim_zero(mlx4_glue->destroy_qp(drop->qp));
 	if (drop->cq)
-		claim_zero(ibv_destroy_cq(drop->cq));
+		claim_zero(mlx4_glue->destroy_cq(drop->cq));
 	if (drop)
 		rte_free(drop);
 	rte_errno = ENOMEM;
@@ -959,8 +961,8 @@ mlx4_drop_put(struct mlx4_drop *drop)
 	if (--drop->refcnt)
 		return;
 	drop->priv->drop = NULL;
-	claim_zero(ibv_destroy_qp(drop->qp));
-	claim_zero(ibv_destroy_cq(drop->cq));
+	claim_zero(mlx4_glue->destroy_qp(drop->qp));
+	claim_zero(mlx4_glue->destroy_cq(drop->cq));
 	rte_free(drop);
 }
 
@@ -992,7 +994,7 @@ mlx4_flow_toggle(struct priv *priv,
 	if (!enable) {
 		if (!flow->ibv_flow)
 			return 0;
-		claim_zero(ibv_destroy_flow(flow->ibv_flow));
+		claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 		flow->ibv_flow = NULL;
 		if (flow->drop)
 			mlx4_drop_put(priv->drop);
@@ -1005,7 +1007,7 @@ mlx4_flow_toggle(struct priv *priv,
 	    !priv->isolated &&
 	    flow->ibv_attr->priority == MLX4_FLOW_PRIORITY_LAST) {
 		if (flow->ibv_flow) {
-			claim_zero(ibv_destroy_flow(flow->ibv_flow));
+			claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 			flow->ibv_flow = NULL;
 			if (flow->drop)
 				mlx4_drop_put(priv->drop);
@@ -1035,7 +1037,7 @@ mlx4_flow_toggle(struct priv *priv,
 			if (missing ^ !flow->drop)
 				return 0;
 			/* Verbs flow needs updating. */
-			claim_zero(ibv_destroy_flow(flow->ibv_flow));
+			claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 			flow->ibv_flow = NULL;
 			if (flow->drop)
 				mlx4_drop_put(priv->drop);
@@ -1067,7 +1069,7 @@ mlx4_flow_toggle(struct priv *priv,
 	assert(qp);
 	if (flow->ibv_flow)
 		return 0;
-	flow->ibv_flow = ibv_create_flow(qp, flow->ibv_attr);
+	flow->ibv_flow = mlx4_glue->create_flow(qp, flow->ibv_attr);
 	if (flow->ibv_flow)
 		return 0;
 	if (flow->drop)
diff --git a/drivers/net/mlx4/mlx4_glue.c b/drivers/net/mlx4/mlx4_glue.c
new file mode 100644
index 000000000..30797bd2b
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_glue.c
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox
+ */
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx4dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#include "mlx4_glue.h"
+
+static int
+mlx4_glue_fork_init(void)
+{
+	return ibv_fork_init();
+}
+
+static int
+mlx4_glue_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
+{
+	return ibv_get_async_event(context, event);
+}
+
+static void
+mlx4_glue_ack_async_event(struct ibv_async_event *event)
+{
+	ibv_ack_async_event(event);
+}
+
+static struct ibv_pd *
+mlx4_glue_alloc_pd(struct ibv_context *context)
+{
+	return ibv_alloc_pd(context);
+}
+
+static int
+mlx4_glue_dealloc_pd(struct ibv_pd *pd)
+{
+	return ibv_dealloc_pd(pd);
+}
+
+static struct ibv_device **
+mlx4_glue_get_device_list(int *num_devices)
+{
+	return ibv_get_device_list(num_devices);
+}
+
+static void
+mlx4_glue_free_device_list(struct ibv_device **list)
+{
+	ibv_free_device_list(list);
+}
+
+static struct ibv_context *
+mlx4_glue_open_device(struct ibv_device *device)
+{
+	return ibv_open_device(device);
+}
+
+static int
+mlx4_glue_close_device(struct ibv_context *context)
+{
+	return ibv_close_device(context);
+}
+
+static const char *
+mlx4_glue_get_device_name(struct ibv_device *device)
+{
+	return ibv_get_device_name(device);
+}
+
+static int
+mlx4_glue_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context, device_attr);
+}
+
+static int
+mlx4_glue_query_device_ex(struct ibv_context *context,
+			  const struct ibv_query_device_ex_input *input,
+			  struct ibv_device_attr_ex *attr)
+{
+	return ibv_query_device_ex(context, input, attr);
+}
+
+static int
+mlx4_glue_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context, port_num, port_attr);
+}
+
+static const char *
+mlx4_glue_port_state_str(enum ibv_port_state port_state)
+{
+	return ibv_port_state_str(port_state);
+}
+
+static struct ibv_comp_channel *
+mlx4_glue_create_comp_channel(struct ibv_context *context)
+{
+	return ibv_create_comp_channel(context);
+}
+
+static int
+mlx4_glue_destroy_comp_channel(struct ibv_comp_channel *channel)
+{
+	return ibv_destroy_comp_channel(channel);
+}
+
+static struct ibv_cq *
+mlx4_glue_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+		    struct ibv_comp_channel *channel, int comp_vector)
+{
+	return ibv_create_cq(context, cqe, cq_context, channel, comp_vector);
+}
+
+static int
+mlx4_glue_destroy_cq(struct ibv_cq *cq)
+{
+	return ibv_destroy_cq(cq);
+}
+
+static int
+mlx4_glue_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
+		       void **cq_context)
+{
+	return ibv_get_cq_event(channel, cq, cq_context);
+}
+
+static void
+mlx4_glue_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq, nevents);
+}
+
+static struct ibv_flow *
+mlx4_glue_create_flow(struct ibv_qp *qp, struct ibv_flow_attr *flow)
+{
+	return ibv_create_flow(qp, flow);
+}
+
+static int
+mlx4_glue_destroy_flow(struct ibv_flow *flow_id)
+{
+	return ibv_destroy_flow(flow_id);
+}
+
+static struct ibv_qp *
+mlx4_glue_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
+{
+	return ibv_create_qp(pd, qp_init_attr);
+}
+
+static struct ibv_qp *
+mlx4_glue_create_qp_ex(struct ibv_context *context,
+		       struct ibv_qp_init_attr_ex *qp_init_attr_ex)
+{
+	return ibv_create_qp_ex(context, qp_init_attr_ex);
+}
+
+static int
+mlx4_glue_destroy_qp(struct ibv_qp *qp)
+{
+	return ibv_destroy_qp(qp);
+}
+
+static int
+mlx4_glue_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
+{
+	return ibv_modify_qp(qp, attr, attr_mask);
+}
+
+static struct ibv_mr *
+mlx4_glue_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access)
+{
+	return ibv_reg_mr(pd, addr, length, access);
+}
+
+static int
+mlx4_glue_dereg_mr(struct ibv_mr *mr)
+{
+	return ibv_dereg_mr(mr);
+}
+
+static struct ibv_rwq_ind_table *
+mlx4_glue_create_rwq_ind_table(struct ibv_context *context,
+			       struct ibv_rwq_ind_table_init_attr *init_attr)
+{
+	return ibv_create_rwq_ind_table(context, init_attr);
+}
+
+static int
+mlx4_glue_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table)
+{
+	return ibv_destroy_rwq_ind_table(rwq_ind_table);
+}
+
+static struct ibv_wq *
+mlx4_glue_create_wq(struct ibv_context *context,
+		    struct ibv_wq_init_attr *wq_init_attr)
+{
+	return ibv_create_wq(context, wq_init_attr);
+}
+
+static int
+mlx4_glue_destroy_wq(struct ibv_wq *wq)
+{
+	return ibv_destroy_wq(wq);
+}
+static int
+mlx4_glue_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr)
+{
+	return ibv_modify_wq(wq, wq_attr);
+}
+
+static int
+mlx4_glue_dv_init_obj(struct mlx4dv_obj *obj, uint64_t obj_type)
+{
+	return mlx4dv_init_obj(obj, obj_type);
+}
+
+static int
+mlx4_glue_dv_set_context_attr(struct ibv_context *context,
+			      enum mlx4dv_set_ctx_attr_type attr_type,
+			      void *attr)
+{
+	return mlx4dv_set_context_attr(context, attr_type, attr);
+}
+
+const struct mlx4_glue *mlx4_glue = &(const struct mlx4_glue){
+	.fork_init = mlx4_glue_fork_init,
+	.get_async_event = mlx4_glue_get_async_event,
+	.ack_async_event = mlx4_glue_ack_async_event,
+	.alloc_pd = mlx4_glue_alloc_pd,
+	.dealloc_pd = mlx4_glue_dealloc_pd,
+	.get_device_list = mlx4_glue_get_device_list,
+	.free_device_list = mlx4_glue_free_device_list,
+	.open_device = mlx4_glue_open_device,
+	.close_device = mlx4_glue_close_device,
+	.get_device_name = mlx4_glue_get_device_name,
+	.query_device = mlx4_glue_query_device,
+	.query_device_ex = mlx4_glue_query_device_ex,
+	.query_port = mlx4_glue_query_port,
+	.port_state_str = mlx4_glue_port_state_str,
+	.create_comp_channel = mlx4_glue_create_comp_channel,
+	.destroy_comp_channel = mlx4_glue_destroy_comp_channel,
+	.create_cq = mlx4_glue_create_cq,
+	.destroy_cq = mlx4_glue_destroy_cq,
+	.get_cq_event = mlx4_glue_get_cq_event,
+	.ack_cq_events = mlx4_glue_ack_cq_events,
+	.create_flow = mlx4_glue_create_flow,
+	.destroy_flow = mlx4_glue_destroy_flow,
+	.create_qp = mlx4_glue_create_qp,
+	.create_qp_ex = mlx4_glue_create_qp_ex,
+	.destroy_qp = mlx4_glue_destroy_qp,
+	.modify_qp = mlx4_glue_modify_qp,
+	.reg_mr = mlx4_glue_reg_mr,
+	.dereg_mr = mlx4_glue_dereg_mr,
+	.create_rwq_ind_table = mlx4_glue_create_rwq_ind_table,
+	.destroy_rwq_ind_table = mlx4_glue_destroy_rwq_ind_table,
+	.create_wq = mlx4_glue_create_wq,
+	.destroy_wq = mlx4_glue_destroy_wq,
+	.modify_wq = mlx4_glue_modify_wq,
+	.dv_init_obj = mlx4_glue_dv_init_obj,
+	.dv_set_context_attr = mlx4_glue_dv_set_context_attr,
+};
diff --git a/drivers/net/mlx4/mlx4_glue.h b/drivers/net/mlx4/mlx4_glue.h
new file mode 100644
index 000000000..0623511f2
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_glue.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox
+ */
+
+#ifndef MLX4_GLUE_H_
+#define MLX4_GLUE_H_
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx4dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+struct mlx4_glue {
+	int (*fork_init)(void);
+	int (*get_async_event)(struct ibv_context *context,
+			       struct ibv_async_event *event);
+	void (*ack_async_event)(struct ibv_async_event *event);
+	struct ibv_pd *(*alloc_pd)(struct ibv_context *context);
+	int (*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_device **(*get_device_list)(int *num_devices);
+	void (*free_device_list)(struct ibv_device **list);
+	struct ibv_context *(*open_device)(struct ibv_device *device);
+	int (*close_device)(struct ibv_context *context);
+	const char *(*get_device_name)(struct ibv_device *device);
+	int (*query_device)(struct ibv_context *context,
+			    struct ibv_device_attr *device_attr);
+	int (*query_device_ex)(struct ibv_context *context,
+			       const struct ibv_query_device_ex_input *input,
+			       struct ibv_device_attr_ex *attr);
+	int (*query_port)(struct ibv_context *context, uint8_t port_num,
+			  struct ibv_port_attr *port_attr);
+	const char *(*port_state_str)(enum ibv_port_state port_state);
+	struct ibv_comp_channel *(*create_comp_channel)
+		(struct ibv_context *context);
+	int (*destroy_comp_channel)(struct ibv_comp_channel *channel);
+	struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe,
+				    void *cq_context,
+				    struct ibv_comp_channel *channel,
+				    int comp_vector);
+	int (*destroy_cq)(struct ibv_cq *cq);
+	int (*get_cq_event)(struct ibv_comp_channel *channel,
+			    struct ibv_cq **cq, void **cq_context);
+	void (*ack_cq_events)(struct ibv_cq *cq, unsigned int nevents);
+	struct ibv_flow *(*create_flow)(struct ibv_qp *qp,
+					struct ibv_flow_attr *flow);
+	int (*destroy_flow)(struct ibv_flow *flow_id);
+	struct ibv_qp *(*create_qp)(struct ibv_pd *pd,
+				    struct ibv_qp_init_attr *qp_init_attr);
+	struct ibv_qp *(*create_qp_ex)
+		(struct ibv_context *context,
+		 struct ibv_qp_init_attr_ex *qp_init_attr_ex);
+	int (*destroy_qp)(struct ibv_qp *qp);
+	int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+			 int attr_mask);
+	struct ibv_mr *(*reg_mr)(struct ibv_pd *pd, void *addr,
+				 size_t length, int access);
+	int (*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_rwq_ind_table *(*create_rwq_ind_table)
+		(struct ibv_context *context,
+		 struct ibv_rwq_ind_table_init_attr *init_attr);
+	int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table);
+	struct ibv_wq *(*create_wq)(struct ibv_context *context,
+				    struct ibv_wq_init_attr *wq_init_attr);
+	int (*destroy_wq)(struct ibv_wq *wq);
+	int (*modify_wq)(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr);
+	int (*dv_init_obj)(struct mlx4dv_obj *obj, uint64_t obj_type);
+	int (*dv_set_context_attr)(struct ibv_context *context,
+				   enum mlx4dv_set_ctx_attr_type attr_type,
+				   void *attr);
+};
+
+const struct mlx4_glue *mlx4_glue;
+
+#endif /* MLX4_GLUE_H_ */
diff --git a/drivers/net/mlx4/mlx4_intr.c b/drivers/net/mlx4/mlx4_intr.c
index 2ff72188a..d5ab170f9 100644
--- a/drivers/net/mlx4/mlx4_intr.c
+++ b/drivers/net/mlx4/mlx4_intr.c
@@ -57,6 +57,7 @@
 #include <rte_interrupts.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -216,7 +217,7 @@ mlx4_interrupt_handler(struct priv *priv)
 	unsigned int i;
 
 	/* Read all message and acknowledge them. */
-	while (!ibv_get_async_event(priv->ctx, &event)) {
+	while (!mlx4_glue->get_async_event(priv->ctx, &event)) {
 		switch (event.event_type) {
 		case IBV_EVENT_PORT_ACTIVE:
 		case IBV_EVENT_PORT_ERR:
@@ -231,7 +232,7 @@ mlx4_interrupt_handler(struct priv *priv)
 			DEBUG("event type %d on physical port %d not handled",
 			      event.event_type, event.element.port_num);
 		}
-		ibv_ack_async_event(&event);
+		mlx4_glue->ack_async_event(&event);
 	}
 	for (i = 0; i != RTE_DIM(caught); ++i)
 		if (caught[i])
@@ -354,7 +355,8 @@ mlx4_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
 	if (!rxq || !rxq->channel) {
 		ret = EINVAL;
 	} else {
-		ret = ibv_get_cq_event(rxq->cq->channel, &ev_cq, &ev_ctx);
+		ret = mlx4_glue->get_cq_event(rxq->cq->channel, &ev_cq,
+					      &ev_ctx);
 		if (ret || ev_cq != rxq->cq)
 			ret = EINVAL;
 	}
@@ -364,7 +366,7 @@ mlx4_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
 		     idx);
 	} else {
 		rxq->mcq.arm_sn++;
-		ibv_ack_cq_events(rxq->cq, 1);
+		mlx4_glue->ack_cq_events(rxq->cq, 1);
 	}
 	return -ret;
 }
diff --git a/drivers/net/mlx4/mlx4_mr.c b/drivers/net/mlx4/mlx4_mr.c
index 2a3e2695b..493c00867 100644
--- a/drivers/net/mlx4/mlx4_mr.c
+++ b/drivers/net/mlx4/mlx4_mr.c
@@ -60,6 +60,7 @@
 #include <rte_mempool.h>
 #include <rte_spinlock.h>
 
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -200,8 +201,8 @@ mlx4_mr_get(struct priv *priv, struct rte_mempool *mp)
 		.end = end,
 		.refcnt = 1,
 		.priv = priv,
-		.mr = ibv_reg_mr(priv->pd, (void *)start, end - start,
-				 IBV_ACCESS_LOCAL_WRITE),
+		.mr = mlx4_glue->reg_mr(priv->pd, (void *)start, end - start,
+					IBV_ACCESS_LOCAL_WRITE),
 		.mp = mp,
 	};
 	if (mr->mr) {
@@ -240,7 +241,7 @@ mlx4_mr_put(struct mlx4_mr *mr)
 	if (--mr->refcnt)
 		goto release;
 	LIST_REMOVE(mr, next);
-	claim_zero(ibv_dereg_mr(mr->mr));
+	claim_zero(mlx4_glue->dereg_mr(mr->mr));
 	rte_free(mr);
 release:
 	rte_spinlock_unlock(&priv->mr_lock);
diff --git a/drivers/net/mlx4/mlx4_rxq.c b/drivers/net/mlx4/mlx4_rxq.c
index 163598765..bf60d2fc8 100644
--- a/drivers/net/mlx4/mlx4_rxq.c
+++ b/drivers/net/mlx4/mlx4_rxq.c
@@ -62,6 +62,7 @@
 #include <rte_mempool.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -231,7 +232,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		}
 		ind_tbl[i] = rxq->wq;
 	}
-	rss->ind = ibv_create_rwq_ind_table
+	rss->ind = mlx4_glue->create_rwq_ind_table
 		(priv->ctx,
 		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = rte_log2_u32(RTE_DIM(ind_tbl)),
@@ -243,7 +244,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "RSS indirection table creation failure";
 		goto error;
 	}
-	rss->qp = ibv_create_qp_ex
+	rss->qp = mlx4_glue->create_qp_ex
 		(priv->ctx,
 		 &(struct ibv_qp_init_attr_ex){
 			.comp_mask = (IBV_QP_INIT_ATTR_PD |
@@ -264,7 +265,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "RSS hash QP creation failure";
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(rss->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_INIT,
@@ -275,7 +276,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "failed to switch RSS hash QP to INIT state";
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(rss->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTR,
@@ -288,11 +289,11 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 	return 0;
 error:
 	if (rss->qp) {
-		claim_zero(ibv_destroy_qp(rss->qp));
+		claim_zero(mlx4_glue->destroy_qp(rss->qp));
 		rss->qp = NULL;
 	}
 	if (rss->ind) {
-		claim_zero(ibv_destroy_rwq_ind_table(rss->ind));
+		claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind));
 		rss->ind = NULL;
 	}
 	while (i--)
@@ -325,9 +326,9 @@ mlx4_rss_detach(struct mlx4_rss *rss)
 	assert(rss->ind);
 	if (--rss->usecnt)
 		return;
-	claim_zero(ibv_destroy_qp(rss->qp));
+	claim_zero(mlx4_glue->destroy_qp(rss->qp));
 	rss->qp = NULL;
-	claim_zero(ibv_destroy_rwq_ind_table(rss->ind));
+	claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind));
 	rss->ind = NULL;
 	for (i = 0; i != rss->queues; ++i)
 		mlx4_rxq_detach(priv->dev->data->rx_queues[rss->queue_id[i]]);
@@ -364,9 +365,10 @@ mlx4_rss_init(struct priv *priv)
 	int ret;
 
 	/* Prepare range for RSS contexts before creating the first WQ. */
-	ret = mlx4dv_set_context_attr(priv->ctx,
-				      MLX4DV_SET_CTX_ATTR_LOG_WQS_RANGE_SZ,
-				      &log2_range);
+	ret = mlx4_glue->dv_set_context_attr
+		(priv->ctx,
+		 MLX4DV_SET_CTX_ATTR_LOG_WQS_RANGE_SZ,
+		 &log2_range);
 	if (ret) {
 		ERROR("cannot set up range size for RSS context to %u"
 		      " (for %u Rx queues), error: %s",
@@ -402,13 +404,13 @@ mlx4_rss_init(struct priv *priv)
 		 * sequentially and are guaranteed to never be reused in the
 		 * same context by the underlying implementation.
 		 */
-		cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+		cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 		if (!cq) {
 			ret = ENOMEM;
 			msg = "placeholder CQ creation failure";
 			goto error;
 		}
-		wq = ibv_create_wq
+		wq = mlx4_glue->create_wq
 			(priv->ctx,
 			 &(struct ibv_wq_init_attr){
 				.wq_type = IBV_WQT_RQ,
@@ -419,11 +421,11 @@ mlx4_rss_init(struct priv *priv)
 			 });
 		if (wq) {
 			wq_num = wq->wq_num;
-			claim_zero(ibv_destroy_wq(wq));
+			claim_zero(mlx4_glue->destroy_wq(wq));
 		} else {
 			wq_num = 0; /* Shut up GCC 4.8 warnings. */
 		}
-		claim_zero(ibv_destroy_cq(cq));
+		claim_zero(mlx4_glue->destroy_cq(cq));
 		if (!wq) {
 			ret = ENOMEM;
 			msg = "placeholder WQ creation failure";
@@ -522,13 +524,14 @@ mlx4_rxq_attach(struct rxq *rxq)
 	int ret;
 
 	assert(rte_is_power_of_2(elts_n));
-	cq = ibv_create_cq(priv->ctx, elts_n / sges_n, NULL, rxq->channel, 0);
+	cq = mlx4_glue->create_cq(priv->ctx, elts_n / sges_n, NULL,
+				  rxq->channel, 0);
 	if (!cq) {
 		ret = ENOMEM;
 		msg = "CQ creation failure";
 		goto error;
 	}
-	wq = ibv_create_wq
+	wq = mlx4_glue->create_wq
 		(priv->ctx,
 		 &(struct ibv_wq_init_attr){
 			.wq_type = IBV_WQT_RQ,
@@ -542,7 +545,7 @@ mlx4_rxq_attach(struct rxq *rxq)
 		msg = "WQ creation failure";
 		goto error;
 	}
-	ret = ibv_modify_wq
+	ret = mlx4_glue->modify_wq
 		(wq,
 		 &(struct ibv_wq_attr){
 			.attr_mask = IBV_WQ_ATTR_STATE,
@@ -557,7 +560,7 @@ mlx4_rxq_attach(struct rxq *rxq)
 	mlxdv.cq.out = &dv_cq;
 	mlxdv.rwq.in = wq;
 	mlxdv.rwq.out = &dv_rwq;
-	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_RWQ | MLX4DV_OBJ_CQ);
+	ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_RWQ | MLX4DV_OBJ_CQ);
 	if (ret) {
 		msg = "failed to obtain device information from WQ/CQ objects";
 		goto error;
@@ -619,9 +622,9 @@ mlx4_rxq_attach(struct rxq *rxq)
 	return 0;
 error:
 	if (wq)
-		claim_zero(ibv_destroy_wq(wq));
+		claim_zero(mlx4_glue->destroy_wq(wq));
 	if (cq)
-		claim_zero(ibv_destroy_cq(cq));
+		claim_zero(mlx4_glue->destroy_cq(cq));
 	rte_errno = ret;
 	ERROR("error while attaching Rx queue %p: %s: %s",
 	      (void *)rxq, msg, strerror(ret));
@@ -649,9 +652,9 @@ mlx4_rxq_detach(struct rxq *rxq)
 	memset(&rxq->mcq, 0, sizeof(rxq->mcq));
 	rxq->rq_db = NULL;
 	rxq->wqes = NULL;
-	claim_zero(ibv_destroy_wq(rxq->wq));
+	claim_zero(mlx4_glue->destroy_wq(rxq->wq));
 	rxq->wq = NULL;
-	claim_zero(ibv_destroy_cq(rxq->cq));
+	claim_zero(mlx4_glue->destroy_cq(rxq->cq));
 	rxq->cq = NULL;
 	DEBUG("%p: freeing Rx queue elements", (void *)rxq);
 	for (i = 0; (i != RTE_DIM(*elts)); ++i) {
@@ -879,7 +882,7 @@ mlx4_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		goto error;
 	}
 	if (dev->data->dev_conf.intr_conf.rxq) {
-		rxq->channel = ibv_create_comp_channel(priv->ctx);
+		rxq->channel = mlx4_glue->create_comp_channel(priv->ctx);
 		if (rxq->channel == NULL) {
 			rte_errno = ENOMEM;
 			ERROR("%p: Rx interrupt completion channel creation"
@@ -934,7 +937,7 @@ mlx4_rx_queue_release(void *dpdk_rxq)
 	assert(!rxq->wqes);
 	assert(!rxq->rq_db);
 	if (rxq->channel)
-		claim_zero(ibv_destroy_comp_channel(rxq->channel));
+		claim_zero(mlx4_glue->destroy_comp_channel(rxq->channel));
 	if (rxq->mr)
 		mlx4_mr_put(rxq->mr);
 	rte_free(rxq);
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 2bd4b9cb6..5e4d701cd 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -60,6 +60,7 @@
 #include <rte_mempool.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_prm.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -350,7 +351,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		.lb = !!priv->vf,
 		.bounce_buf = bounce_buf,
 	};
-	txq->cq = ibv_create_cq(priv->ctx, desc, NULL, NULL, 0);
+	txq->cq = mlx4_glue->create_cq(priv->ctx, desc, NULL, NULL, 0);
 	if (!txq->cq) {
 		rte_errno = ENOMEM;
 		ERROR("%p: CQ creation failure: %s",
@@ -370,7 +371,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		/* No completion events must occur by default. */
 		.sq_sig_all = 0,
 	};
-	txq->qp = ibv_create_qp(priv->pd, &qp_init_attr);
+	txq->qp = mlx4_glue->create_qp(priv->pd, &qp_init_attr);
 	if (!txq->qp) {
 		rte_errno = errno ? errno : EINVAL;
 		ERROR("%p: QP creation failure: %s",
@@ -378,7 +379,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		goto error;
 	}
 	txq->max_inline = qp_init_attr.cap.max_inline_data;
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_INIT,
@@ -391,7 +392,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTR,
@@ -403,7 +404,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTS,
@@ -420,7 +421,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 	mlxdv.cq.out = &dv_cq;
 	mlxdv.qp.in = txq->qp;
 	mlxdv.qp.out = &dv_qp;
-	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
+	ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
 	if (ret) {
 		rte_errno = EINVAL;
 		ERROR("%p: failed to obtain information needed for"
@@ -470,9 +471,9 @@ mlx4_tx_queue_release(void *dpdk_txq)
 		}
 	mlx4_txq_free_elts(txq);
 	if (txq->qp)
-		claim_zero(ibv_destroy_qp(txq->qp));
+		claim_zero(mlx4_glue->destroy_qp(txq->qp));
 	if (txq->cq)
-		claim_zero(ibv_destroy_cq(txq->cq));
+		claim_zero(mlx4_glue->destroy_cq(txq->cq));
 	for (i = 0; i != RTE_DIM(txq->mp2mr); ++i) {
 		if (!txq->mp2mr[i].mp)
 			break;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v1 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-24 23:24 [PATCH v1 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  2018-01-24 23:25 ` [PATCH v1 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
@ 2018-01-24 23:25 ` Adrien Mazarguil
  2018-01-26 10:06   ` Thomas Monjalon
  2018-01-24 23:25 ` [PATCH v1 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-24 23:25 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

When mlx4 is not compiled directly as an independent shared object (e.g.
CONFIG_RTE_BUILD_SHARED_LIB not enabled for performance reasons), DPDK
applications inherit its dependencies on libibverbs and libmlx4 through
rte.app.mk.

This is an issue both when DPDK is delivered as a binary package (Linux
distributions) and for end users because rdma-core then propagates as a
mandatory dependency for everything.

Application writers relying on binary DPDK packages are not necessarily
aware of this fact and may end up delivering packages with broken
dependencies.

This patch therefore introduces an intermediate internal plug-in
hard-linked with rdma-core (to preserve symbol versioning) loaded by the
PMD through dlopen(), so that a missing rdma-core does not cause unresolved
symbols, allowing applications to start normally.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 drivers/net/mlx4/Makefile | 40 +++++++++++++++++++++
 drivers/net/mlx4/mlx4.c   | 80 ++++++++++++++++++++++++++++++++++++++++++
 mk/rte.app.mk             |  2 +-
 3 files changed, 121 insertions(+), 1 deletion(-)

diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1d33c38ed..2ebe61e90 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -38,7 +38,11 @@ LIB = librte_pmd_mlx4.a
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_flow.c
+ifneq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue_lib.c
+else
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue.c
+endif
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_intr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxq.c
@@ -55,7 +59,12 @@ CFLAGS += -D_BSD_SOURCE
 CFLAGS += -D_DEFAULT_SOURCE
 CFLAGS += -D_XOPEN_SOURCE=600
 CFLAGS += $(WERROR_FLAGS)
+ifneq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+CFLAGS_mlx4_glue.o += -fPIC
+LDLIBS += -ldl
+else
 LDLIBS += -libverbs -lmlx4
+endif
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
@@ -109,7 +118,38 @@ mlx4_autoconf.h: mlx4_autoconf.h.new
 
 $(SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD):.c=.o): mlx4_autoconf.h
 
+# Generate dependency plug-in for rdma-core when the PMD cannot be linked
+# directly, so that applications do not inherit this dependency.
+
+ifneq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+
+mlx4_glue_lib.c: mlx4_glue_lib.so
+	$Q printf '#include <stddef.h>\n' > $@
+	$Q printf '#include <stdint.h>\n\n' >> $@
+	$Q printf 'const uint8_t mlx4_glue_lib[][16] = {\n' >> $@
+	$Q od -vt x1 $< | \
+	sed -ne '/^[[:xdigit:]]\{1,\}/{' \
+		-e 's///;' \
+		-e '/^$$/d; ' \
+		-e 's/[[:space:]]*$$//;' \
+		-e 's/[[:space:]]\{1,\}/\\x/g;' \
+		-e 's/^/	"/;' \
+		-e 's/$$/",/;' \
+		-e 'p;' \
+		-e '}' >> $@
+	$Q printf '};\n\n' >> $@
+	$Q printf 'const size_t mlx4_glue_lib_size = %u;' $$(wc -c < $<) >> $@
+
+mlx4_glue_lib.so: mlx4_glue.o
+	$Q $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) \
+		-s -shared -o $@ $< -libverbs -lmlx4
+
+mlx4_glue.o: mlx4_autoconf.h
+
+endif
+
 clean_mlx4: FORCE
 	$Q rm -f -- mlx4_autoconf.h mlx4_autoconf.h.new
+	$Q rm -f -- mlx4_glue.o mlx4_glue_lib.*
 
 clean: clean_mlx4
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 0fd9a999c..c173fbf56 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -37,6 +37,7 @@
  */
 
 #include <assert.h>
+#include <dlfcn.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <stddef.h>
@@ -44,6 +45,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 /* Verbs headers do not support -pedantic. */
 #ifdef PEDANTIC
@@ -55,6 +57,7 @@
 #endif
 
 #include <rte_common.h>
+#include <rte_config.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
 #include <rte_ethdev_driver.h>
@@ -724,6 +727,78 @@ static struct rte_pci_driver mlx4_driver = {
 		     RTE_PCI_DRV_INTR_RMV,
 };
 
+#ifndef RTE_BUILD_SHARED_LIB
+
+extern const uint8_t mlx4_glue_lib[][16];
+extern const size_t mlx4_glue_lib_size;
+
+/**
+ * Initialization routine for run-time dependency on rdma-core.
+ */
+static int
+mlx4_glue_init(void)
+{
+	char file[] = "/tmp/" MLX4_DRIVER_NAME "_XXXXXX";
+	int fd = mkstemp(file);
+	size_t off = 0;
+	void *handle = NULL;
+	void **sym;
+	const char *dlmsg;
+
+	if (fd == -1) {
+		rte_errno = errno;
+		goto glue_error;
+	}
+	while (off != mlx4_glue_lib_size) {
+		ssize_t ret;
+
+		ret = write(fd, (const uint8_t *)mlx4_glue_lib + off,
+			    mlx4_glue_lib_size - off);
+		if (ret == -1) {
+			if (errno != EINTR) {
+				rte_errno = errno;
+				goto glue_error;
+			}
+			ret = 0;
+		}
+		off += ret;
+	}
+	close(fd);
+	fd = -1;
+	handle = dlopen(file, RTLD_LAZY);
+	unlink(file);
+	if (!handle) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot load glue library: %s", dlmsg);
+		goto glue_error;
+	}
+	sym = dlsym(handle, "mlx4_glue");
+	if (!sym || !*sym) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot resolve glue symbol: %s", dlmsg);
+		goto glue_error;
+	}
+	mlx4_glue = *sym;
+	return 0;
+glue_error:
+	if (handle)
+		dlclose(handle);
+	if (fd != -1) {
+		close(fd);
+		unlink(file);
+	}
+	ERROR("cannot initialize PMD due to missing run-time"
+	      " dependency on rdma-core libraries (libibverbs,"
+	      " libmlx4)");
+	return -rte_errno;
+}
+
+#endif
+
 /**
  * Driver initialization routine.
  */
@@ -744,6 +819,11 @@ rte_mlx4_pmd_init(void)
 	 * using this PMD, which is not supported in forked processes.
 	 */
 	setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
+#ifndef RTE_BUILD_SHARED_LIB
+	if (mlx4_glue_init())
+		return;
+	assert(mlx4_glue);
+#endif
 	mlx4_glue->fork_init();
 	rte_pci_register(&mlx4_driver);
 }
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 0169f3f5b..f9ac0e620 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -143,7 +143,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KNI)        += -lrte_pmd_kni
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio
-_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs -lmlx4
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -ldl
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs -lmlx5
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v1 3/4] net/mlx5: move rdma-core calls to separate file
  2018-01-24 23:24 [PATCH v1 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  2018-01-24 23:25 ` [PATCH v1 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
  2018-01-24 23:25 ` [PATCH v1 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-24 23:25 ` Adrien Mazarguil
  2018-01-24 23:25 ` [PATCH v1 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
  2018-01-26 14:18 ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  4 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-24 23:25 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

From: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>

This lays the groundwork for externalizing rdma-core as an optional
run-time dependency instead of a mandatory one.

No functional change.

Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
---
 drivers/net/mlx5/Makefile        |   1 +
 drivers/net/mlx5/mlx5.c          |  48 ++---
 drivers/net/mlx5/mlx5_ethdev.c   |   7 +-
 drivers/net/mlx5/mlx5_flow.c     |  71 ++++----
 drivers/net/mlx5/mlx5_glue.c     | 328 ++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h     | 100 +++++++++++
 drivers/net/mlx5/mlx5_mac.c      |   1 +
 drivers/net/mlx5/mlx5_mr.c       |   7 +-
 drivers/net/mlx5/mlx5_rss.c      |   1 +
 drivers/net/mlx5/mlx5_rxmode.c   |   1 +
 drivers/net/mlx5/mlx5_rxq.c      |  54 +++---
 drivers/net/mlx5/mlx5_rxtx.c     |   1 +
 drivers/net/mlx5/mlx5_rxtx.h     |   1 +
 drivers/net/mlx5/mlx5_rxtx_vec.c |   1 +
 drivers/net/mlx5/mlx5_txq.c      |  22 +--
 drivers/net/mlx5/mlx5_vlan.c     |   2 +-
 16 files changed, 541 insertions(+), 105 deletions(-)

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index a3984eb9f..bdec30692 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -53,6 +53,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
 
 # Basic CFLAGS.
 CFLAGS += -O3
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index bc4b6bad0..b36cc611f 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -63,6 +63,7 @@
 #include "mlx5_rxtx.h"
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
+#include "mlx5_glue.h"
 
 /* Device parameter to enable RX completion queue compression. */
 #define MLX5_RXQ_CQE_COMP_EN "rxq_cqe_comp_en"
@@ -216,8 +217,8 @@ mlx5_dev_close(struct rte_eth_dev *dev)
 	}
 	if (priv->pd != NULL) {
 		assert(priv->ctx != NULL);
-		claim_zero(ibv_dealloc_pd(priv->pd));
-		claim_zero(ibv_close_device(priv->ctx));
+		claim_zero(mlx5_glue->dealloc_pd(priv->pd));
+		claim_zero(mlx5_glue->close_device(priv->ctx));
 	} else
 		assert(priv->ctx == NULL);
 	if (priv->rss_conf.rss_key != NULL)
@@ -523,7 +524,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 	/* Save PCI address. */
 	mlx5_dev[idx].pci_addr = pci_dev->addr;
-	list = ibv_get_device_list(&i);
+	list = mlx5_glue->get_device_list(&i);
 	if (list == NULL) {
 		assert(errno);
 		if (errno == ENOSYS)
@@ -573,12 +574,12 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		     " (SR-IOV: %s)",
 		     list[i]->name,
 		     sriov ? "true" : "false");
-		attr_ctx = ibv_open_device(list[i]);
+		attr_ctx = mlx5_glue->open_device(list[i]);
 		err = errno;
 		break;
 	}
 	if (attr_ctx == NULL) {
-		ibv_free_device_list(list);
+		mlx5_glue->free_device_list(list);
 		switch (err) {
 		case 0:
 			ERROR("cannot access device, is mlx5_ib loaded?");
@@ -597,7 +598,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	 * Multi-packet send is supported by ConnectX-4 Lx PF as well
 	 * as all ConnectX-5 devices.
 	 */
-	mlx5dv_query_device(attr_ctx, &attrs_out);
+	mlx5_glue->dv_query_device(attr_ctx, &attrs_out);
 	if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_MPW_ALLOWED) {
 		if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_ENHANCED_MPW) {
 			DEBUG("Enhanced MPW is supported");
@@ -615,7 +616,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		cqe_comp = 0;
 	else
 		cqe_comp = 1;
-	if (ibv_query_device_ex(attr_ctx, NULL, &device_attr))
+	if (mlx5_glue->query_device_ex(attr_ctx, NULL, &device_attr))
 		goto error;
 	INFO("%u port(s) detected", device_attr.orig_attr.phys_port_cnt);
 
@@ -650,7 +651,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			char name[RTE_ETH_NAME_MAX_LEN];
 
 			snprintf(name, sizeof(name), "%s port %u",
-				 ibv_get_device_name(ibv_dev), port);
+				 mlx5_glue->get_device_name(ibv_dev), port);
 			eth_dev = rte_eth_dev_attach_secondary(name);
 			if (eth_dev == NULL) {
 				ERROR("can not attach rte ethdev");
@@ -686,15 +687,15 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 		DEBUG("using port %u (%08" PRIx32 ")", port, test);
 
-		ctx = ibv_open_device(ibv_dev);
+		ctx = mlx5_glue->open_device(ibv_dev);
 		if (ctx == NULL) {
 			err = ENODEV;
 			goto port_error;
 		}
 
-		ibv_query_device_ex(ctx, NULL, &device_attr);
+		mlx5_glue->query_device_ex(ctx, NULL, &device_attr);
 		/* Check port status. */
-		err = ibv_query_port(ctx, port, &port_attr);
+		err = mlx5_glue->query_port(ctx, port, &port_attr);
 		if (err) {
 			ERROR("port query failed: %s", strerror(err));
 			goto port_error;
@@ -709,11 +710,11 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 		if (port_attr.state != IBV_PORT_ACTIVE)
 			DEBUG("port %d is not active: \"%s\" (%d)",
-			      port, ibv_port_state_str(port_attr.state),
+			      port, mlx5_glue->port_state_str(port_attr.state),
 			      port_attr.state);
 
 		/* Allocate protection domain. */
-		pd = ibv_alloc_pd(ctx);
+		pd = mlx5_glue->alloc_pd(ctx);
 		if (pd == NULL) {
 			ERROR("PD allocation failure");
 			err = ENOMEM;
@@ -745,7 +746,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			      strerror(err));
 			goto port_error;
 		}
-		if (ibv_query_device_ex(ctx, NULL, &device_attr_ex)) {
+		if (mlx5_glue->query_device_ex(ctx, NULL, &device_attr_ex)) {
 			ERROR("ibv_query_device_ex() failed");
 			goto port_error;
 		}
@@ -765,7 +766,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
 		config.flow_counter_en = !!(device_attr.max_counter_sets);
-		ibv_describe_counter_set(ctx, 0, &cs_desc);
+		mlx5_glue->describe_counter_set(ctx, 0, &cs_desc);
 		DEBUG("counter type = %d, num of cs = %ld, attributes = %d",
 		      cs_desc.counter_type, cs_desc.num_of_cs,
 		      cs_desc.attributes);
@@ -849,7 +850,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			char name[RTE_ETH_NAME_MAX_LEN];
 
 			snprintf(name, sizeof(name), "%s port %u",
-				 ibv_get_device_name(ibv_dev), port);
+				 mlx5_glue->get_device_name(ibv_dev), port);
 			eth_dev = rte_eth_dev_allocate(name);
 		}
 		if (eth_dev == NULL) {
@@ -875,8 +876,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			.free = &mlx5_free_verbs_buf,
 			.data = priv,
 		};
-		mlx5dv_set_context_attr(ctx, MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
-					(void *)((uintptr_t)&alctr));
+		mlx5_glue->dv_set_context_attr(ctx,
+					       MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
+					       (void *)((uintptr_t)&alctr));
 
 		/* Bring Ethernet device up. */
 		DEBUG("forcing Ethernet interface up");
@@ -889,9 +891,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		if (priv)
 			rte_free(priv);
 		if (pd)
-			claim_zero(ibv_dealloc_pd(pd));
+			claim_zero(mlx5_glue->dealloc_pd(pd));
 		if (ctx)
-			claim_zero(ibv_close_device(ctx));
+			claim_zero(mlx5_glue->close_device(ctx));
 		break;
 	}
 
@@ -910,9 +912,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 error:
 	if (attr_ctx)
-		claim_zero(ibv_close_device(attr_ctx));
+		claim_zero(mlx5_glue->close_device(attr_ctx));
 	if (list)
-		ibv_free_device_list(list);
+		mlx5_glue->free_device_list(list);
 	assert(err >= 0);
 	return -err;
 }
@@ -983,7 +985,7 @@ rte_mlx5_pmd_init(void)
 	/* Match the size of Rx completion entry to the size of a cacheline. */
 	if (RTE_CACHE_LINE_SIZE == 128)
 		setenv("MLX5_CQE_SIZE", "128", 0);
-	ibv_fork_init();
+	mlx5_glue->fork_init();
 	rte_pci_register(&mlx5_driver);
 }
 
diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c
index 6624888c9..37c3afe44 100644
--- a/drivers/net/mlx5/mlx5_ethdev.c
+++ b/drivers/net/mlx5/mlx5_ethdev.c
@@ -64,6 +64,7 @@
 #include <rte_malloc.h>
 
 #include "mlx5.h"
+#include "mlx5_glue.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_utils.h"
 
@@ -1233,7 +1234,7 @@ priv_dev_status_handler(struct priv *priv)
 
 	/* Read all message and acknowledge them. */
 	for (;;) {
-		if (ibv_get_async_event(priv->ctx, &event))
+		if (mlx5_glue->get_async_event(priv->ctx, &event))
 			break;
 		if ((event.event_type == IBV_EVENT_PORT_ACTIVE ||
 			event.event_type == IBV_EVENT_PORT_ERR) &&
@@ -1245,7 +1246,7 @@ priv_dev_status_handler(struct priv *priv)
 		else
 			DEBUG("event type %d on port %d not handled",
 			      event.event_type, event.element.port_num);
-		ibv_ack_async_event(&event);
+		mlx5_glue->ack_async_event(&event);
 	}
 	if (ret & (1 << RTE_ETH_EVENT_INTR_LSC))
 		if (priv_link_status_update(priv))
@@ -1531,7 +1532,7 @@ mlx5_is_removed(struct rte_eth_dev *dev)
 	struct ibv_device_attr device_attr;
 	struct priv *priv = dev->data->dev_private;
 
-	if (ibv_query_device(priv->ctx, &device_attr) == EIO)
+	if (mlx5_glue->query_device(priv->ctx, &device_attr) == EIO)
 		return 1;
 	return 0;
 }
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 20c418536..399e67a8a 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -53,6 +53,7 @@
 #include "mlx5.h"
 #include "mlx5_defs.h"
 #include "mlx5_prm.h"
+#include "mlx5_glue.h"
 
 /* Define minimal priority for control plane flows. */
 #define MLX5_CTRL_FLOW_PRIORITY 4
@@ -62,22 +63,9 @@
 #define MLX5_IPV6 6
 
 #ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
-struct ibv_counter_set_init_attr {
-	int dummy;
-};
 struct ibv_flow_spec_counter_action {
 	int dummy;
 };
-struct ibv_counter_set {
-	int dummy;
-};
-
-static inline int
-ibv_destroy_counter_set(struct ibv_counter_set *cs)
-{
-	(void)cs;
-	return -ENOTSUP;
-}
 #endif
 
 /* Dev ops structure defined in mlx5.c */
@@ -1648,7 +1636,7 @@ mlx5_flow_create_count(struct priv *priv __rte_unused,
 	};
 
 	init_attr.counter_set_id = 0;
-	parser->cs = ibv_create_counter_set(priv->ctx, &init_attr);
+	parser->cs = mlx5_glue->create_counter_set(priv->ctx, &init_attr);
 	if (!parser->cs)
 		return EINVAL;
 	counter.counter_set_handle = parser->cs->handle;
@@ -1701,7 +1689,7 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 		return 0;
 	parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
 	flow->frxq[HASH_RXQ_ETH].ibv_flow =
-		ibv_create_flow(priv->flow_drop_queue->qp,
+		mlx5_glue->create_flow(priv->flow_drop_queue->qp,
 				flow->frxq[HASH_RXQ_ETH].ibv_attr);
 	if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
 		rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
@@ -1713,7 +1701,8 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 error:
 	assert(flow);
 	if (flow->frxq[HASH_RXQ_ETH].ibv_flow) {
-		claim_zero(ibv_destroy_flow(flow->frxq[HASH_RXQ_ETH].ibv_flow));
+		claim_zero(mlx5_glue->destroy_flow
+				(flow->frxq[HASH_RXQ_ETH].ibv_flow));
 		flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
 	}
 	if (flow->frxq[HASH_RXQ_ETH].ibv_attr) {
@@ -1721,7 +1710,7 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 		flow->frxq[HASH_RXQ_ETH].ibv_attr = NULL;
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 		parser->cs = NULL;
 	}
@@ -1825,7 +1814,7 @@ priv_flow_create_action_queue(struct priv *priv,
 		if (!flow->frxq[i].hrxq)
 			continue;
 		flow->frxq[i].ibv_flow =
-			ibv_create_flow(flow->frxq[i].hrxq->qp,
+			mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
 					flow->frxq[i].ibv_attr);
 		if (!flow->frxq[i].ibv_flow) {
 			rte_flow_error_set(error, ENOMEM,
@@ -1852,7 +1841,7 @@ priv_flow_create_action_queue(struct priv *priv,
 		if (flow->frxq[i].ibv_flow) {
 			struct ibv_flow *ibv_flow = flow->frxq[i].ibv_flow;
 
-			claim_zero(ibv_destroy_flow(ibv_flow));
+			claim_zero(mlx5_glue->destroy_flow(ibv_flow));
 		}
 		if (flow->frxq[i].hrxq)
 			mlx5_priv_hrxq_release(priv, flow->frxq[i].hrxq);
@@ -1860,7 +1849,7 @@ priv_flow_create_action_queue(struct priv *priv,
 			rte_free(flow->frxq[i].ibv_attr);
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 		parser->cs = NULL;
 	}
@@ -2038,7 +2027,7 @@ priv_flow_destroy(struct priv *priv,
 free:
 	if (flow->drop) {
 		if (flow->frxq[HASH_RXQ_ETH].ibv_flow)
-			claim_zero(ibv_destroy_flow
+			claim_zero(mlx5_glue->destroy_flow
 				   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 		rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
 	} else {
@@ -2046,7 +2035,8 @@ priv_flow_destroy(struct priv *priv,
 			struct mlx5_flow *frxq = &flow->frxq[i];
 
 			if (frxq->ibv_flow)
-				claim_zero(ibv_destroy_flow(frxq->ibv_flow));
+				claim_zero(mlx5_glue->destroy_flow
+						(frxq->ibv_flow));
 			if (frxq->hrxq)
 				mlx5_priv_hrxq_release(priv, frxq->hrxq);
 			if (frxq->ibv_attr)
@@ -2054,7 +2044,7 @@ priv_flow_destroy(struct priv *priv,
 		}
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 	}
 	TAILQ_REMOVE(list, flow, next);
@@ -2102,12 +2092,12 @@ priv_flow_create_drop_queue(struct priv *priv)
 		WARN("cannot allocate memory for drop queue");
 		goto error;
 	}
-	fdq->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+	fdq->cq = mlx5_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 	if (!fdq->cq) {
 		WARN("cannot allocate CQ for drop queue");
 		goto error;
 	}
-	fdq->wq = ibv_create_wq(priv->ctx,
+	fdq->wq = mlx5_glue->create_wq(priv->ctx,
 			&(struct ibv_wq_init_attr){
 			.wq_type = IBV_WQT_RQ,
 			.max_wr = 1,
@@ -2119,7 +2109,7 @@ priv_flow_create_drop_queue(struct priv *priv)
 		WARN("cannot allocate WQ for drop queue");
 		goto error;
 	}
-	fdq->ind_table = ibv_create_rwq_ind_table(priv->ctx,
+	fdq->ind_table = mlx5_glue->create_rwq_ind_table(priv->ctx,
 			&(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = 0,
 			.ind_tbl = &fdq->wq,
@@ -2129,7 +2119,7 @@ priv_flow_create_drop_queue(struct priv *priv)
 		WARN("cannot allocate indirection table for drop queue");
 		goto error;
 	}
-	fdq->qp = ibv_create_qp_ex(priv->ctx,
+	fdq->qp = mlx5_glue->create_qp_ex(priv->ctx,
 		&(struct ibv_qp_init_attr_ex){
 			.qp_type = IBV_QPT_RAW_PACKET,
 			.comp_mask =
@@ -2154,13 +2144,13 @@ priv_flow_create_drop_queue(struct priv *priv)
 	return 0;
 error:
 	if (fdq->qp)
-		claim_zero(ibv_destroy_qp(fdq->qp));
+		claim_zero(mlx5_glue->destroy_qp(fdq->qp));
 	if (fdq->ind_table)
-		claim_zero(ibv_destroy_rwq_ind_table(fdq->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
 	if (fdq->wq)
-		claim_zero(ibv_destroy_wq(fdq->wq));
+		claim_zero(mlx5_glue->destroy_wq(fdq->wq));
 	if (fdq->cq)
-		claim_zero(ibv_destroy_cq(fdq->cq));
+		claim_zero(mlx5_glue->destroy_cq(fdq->cq));
 	if (fdq)
 		rte_free(fdq);
 	priv->flow_drop_queue = NULL;
@@ -2181,13 +2171,13 @@ priv_flow_delete_drop_queue(struct priv *priv)
 	if (!fdq)
 		return;
 	if (fdq->qp)
-		claim_zero(ibv_destroy_qp(fdq->qp));
+		claim_zero(mlx5_glue->destroy_qp(fdq->qp));
 	if (fdq->ind_table)
-		claim_zero(ibv_destroy_rwq_ind_table(fdq->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
 	if (fdq->wq)
-		claim_zero(ibv_destroy_wq(fdq->wq));
+		claim_zero(mlx5_glue->destroy_wq(fdq->wq));
 	if (fdq->cq)
-		claim_zero(ibv_destroy_cq(fdq->cq));
+		claim_zero(mlx5_glue->destroy_cq(fdq->cq));
 	rte_free(fdq);
 	priv->flow_drop_queue = NULL;
 }
@@ -2211,7 +2201,7 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
 		if (flow->drop) {
 			if (!flow->frxq[HASH_RXQ_ETH].ibv_flow)
 				continue;
-			claim_zero(ibv_destroy_flow
+			claim_zero(mlx5_glue->destroy_flow
 				   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 			flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
 			/* Next flow. */
@@ -2232,7 +2222,8 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
 		for (i = 0; i != hash_rxq_init_n; ++i) {
 			if (!flow->frxq[i].ibv_flow)
 				continue;
-			claim_zero(ibv_destroy_flow(flow->frxq[i].ibv_flow));
+			claim_zero(mlx5_glue->destroy_flow
+					(flow->frxq[i].ibv_flow));
 			flow->frxq[i].ibv_flow = NULL;
 			mlx5_priv_hrxq_release(priv, flow->frxq[i].hrxq);
 			flow->frxq[i].hrxq = NULL;
@@ -2262,7 +2253,7 @@ priv_flow_start(struct priv *priv, struct mlx5_flows *list)
 
 		if (flow->drop) {
 			flow->frxq[HASH_RXQ_ETH].ibv_flow =
-				ibv_create_flow
+				mlx5_glue->create_flow
 				(priv->flow_drop_queue->qp,
 				 flow->frxq[HASH_RXQ_ETH].ibv_attr);
 			if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
@@ -2300,7 +2291,7 @@ priv_flow_start(struct priv *priv, struct mlx5_flows *list)
 			}
 flow_create:
 			flow->frxq[i].ibv_flow =
-				ibv_create_flow(flow->frxq[i].hrxq->qp,
+				mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
 						flow->frxq[i].ibv_attr);
 			if (!flow->frxq[i].ibv_flow) {
 				DEBUG("Flow %p cannot be applied",
@@ -2508,7 +2499,7 @@ priv_flow_query_count(struct ibv_counter_set *cs,
 		.out = counters,
 		.outlen = 2 * sizeof(uint64_t),
 	};
-	int res = ibv_query_counter_set(&query_cs_attr, &query_out);
+	int res = mlx5_glue->query_counter_set(&query_cs_attr, &query_out);
 
 	if (res) {
 		rte_flow_error_set(error, -res,
diff --git a/drivers/net/mlx5/mlx5_glue.c b/drivers/net/mlx5/mlx5_glue.c
new file mode 100644
index 000000000..36c4625f4
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_glue.c
@@ -0,0 +1,328 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox Technologies, Ltd.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
+
+static int
+mlx5_glue_fork_init(void)
+{
+	return ibv_fork_init();
+}
+
+static struct ibv_pd *
+mlx5_glue_alloc_pd(struct ibv_context *context)
+{
+	return ibv_alloc_pd(context);
+}
+
+static int
+mlx5_glue_dealloc_pd(struct ibv_pd *pd)
+{
+	return ibv_dealloc_pd(pd);
+}
+
+static struct ibv_device **
+mlx5_glue_get_device_list(int *num_devices)
+{
+	return ibv_get_device_list(num_devices);
+}
+
+static void
+mlx5_glue_free_device_list(struct ibv_device **list)
+{
+	ibv_free_device_list(list);
+}
+
+static struct ibv_context *
+mlx5_glue_open_device(struct ibv_device *device)
+{
+	return ibv_open_device(device);
+}
+
+static int
+mlx5_glue_close_device(struct ibv_context *context)
+{
+	return ibv_close_device(context);
+}
+
+static const char *
+mlx5_glue_get_device_name(struct ibv_device *device)
+{
+	return ibv_get_device_name(device);
+}
+
+static int
+mlx5_glue_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context, device_attr);
+}
+
+static int
+mlx5_glue_query_device_ex(struct ibv_context *context,
+			  const struct ibv_query_device_ex_input *input,
+			  struct ibv_device_attr_ex *attr)
+{
+	return ibv_query_device_ex(context, input, attr);
+}
+
+static int
+mlx5_glue_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context, port_num, port_attr);
+}
+
+static struct ibv_comp_channel *
+mlx5_glue_create_comp_channel(struct ibv_context *context)
+{
+	return ibv_create_comp_channel(context);
+}
+
+static int
+mlx5_glue_destroy_comp_channel(struct ibv_comp_channel *channel)
+{
+	return ibv_destroy_comp_channel(channel);
+}
+
+static struct ibv_cq *
+mlx5_glue_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+		    struct ibv_comp_channel *channel, int comp_vector)
+{
+	return ibv_create_cq(context, cqe, cq_context, channel, comp_vector);
+}
+
+static int
+mlx5_glue_destroy_cq(struct ibv_cq *cq)
+{
+	return ibv_destroy_cq(cq);
+}
+
+static int
+mlx5_glue_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
+		       void **cq_context)
+{
+	return ibv_get_cq_event(channel, cq, cq_context);
+}
+
+static void
+mlx5_glue_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq, nevents);
+}
+
+static struct ibv_rwq_ind_table *
+mlx5_glue_create_rwq_ind_table(struct ibv_context *context,
+			       struct ibv_rwq_ind_table_init_attr *init_attr)
+{
+	return ibv_create_rwq_ind_table(context, init_attr);
+}
+
+static int
+mlx5_glue_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table)
+{
+	return ibv_destroy_rwq_ind_table(rwq_ind_table);
+}
+
+static struct ibv_wq *
+mlx5_glue_create_wq(struct ibv_context *context,
+		    struct ibv_wq_init_attr *wq_init_attr)
+{
+	return ibv_create_wq(context, wq_init_attr);
+}
+
+static int
+mlx5_glue_destroy_wq(struct ibv_wq *wq)
+{
+	return ibv_destroy_wq(wq);
+}
+static int
+mlx5_glue_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr)
+{
+	return ibv_modify_wq(wq, wq_attr);
+}
+
+static struct ibv_flow *
+mlx5_glue_create_flow(struct ibv_qp *qp, struct ibv_flow_attr *flow)
+{
+	return ibv_create_flow(qp, flow);
+}
+
+static int
+mlx5_glue_destroy_flow(struct ibv_flow *flow_id)
+{
+	return ibv_destroy_flow(flow_id);
+}
+
+static struct ibv_qp *
+mlx5_glue_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
+{
+	return ibv_create_qp(pd, qp_init_attr);
+}
+
+static struct ibv_qp *
+mlx5_glue_create_qp_ex(struct ibv_context *context,
+		       struct ibv_qp_init_attr_ex *qp_init_attr_ex)
+{
+	return ibv_create_qp_ex(context, qp_init_attr_ex);
+}
+
+static int
+mlx5_glue_destroy_qp(struct ibv_qp *qp)
+{
+	return ibv_destroy_qp(qp);
+}
+
+static int
+mlx5_glue_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
+{
+	return ibv_modify_qp(qp, attr, attr_mask);
+}
+
+static struct ibv_mr *
+mlx5_glue_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access)
+{
+	return ibv_reg_mr(pd, addr, length, access);
+}
+
+static int
+mlx5_glue_dereg_mr(struct ibv_mr *mr)
+{
+	return ibv_dereg_mr(mr);
+}
+
+static struct ibv_counter_set *
+mlx5_glue_create_counter_set(struct ibv_context *context,
+			     struct ibv_counter_set_init_attr *init_attr)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)context;
+	(void)init_attr;
+	return NULL;
+#else
+	return ibv_create_counter_set(context, init_attr);
+#endif
+}
+
+static inline int
+mlx5_glue_destroy_counter_set(struct ibv_counter_set *cs)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)cs;
+	return -ENOTSUP;
+#else
+	return ibv_destroy_counter_set(cs);
+#endif
+}
+
+static void
+mlx5_glue_ack_async_event(struct ibv_async_event *event)
+{
+	ibv_ack_async_event(event);
+}
+
+static int
+mlx5_glue_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
+{
+	return ibv_get_async_event(context, event);
+}
+
+static const char *
+mlx5_glue_port_state_str(enum ibv_port_state port_state)
+{
+	return ibv_port_state_str(port_state);
+}
+
+static struct ibv_cq *
+mlx5_glue_cq_ex_to_cq(struct ibv_cq_ex *cq)
+{
+	return ibv_cq_ex_to_cq(cq);
+}
+
+static struct ibv_cq_ex *
+mlx5_glue_dv_create_cq(struct ibv_context *context,
+		       struct ibv_cq_init_attr_ex *cq_attr,
+		       struct mlx5dv_cq_init_attr *mlx5_cq_attr)
+{
+	return mlx5dv_create_cq(context, cq_attr, mlx5_cq_attr);
+}
+
+static int
+mlx5_glue_dv_query_device(struct ibv_context *ctx,
+			  struct mlx5dv_context *attrs_out)
+{
+	return mlx5dv_query_device(ctx, attrs_out);
+}
+
+static int
+mlx5_glue_dv_set_context_attr(struct ibv_context *ibv_ctx,
+			      enum mlx5dv_set_ctx_attr_type type, void *attr)
+{
+	return mlx5dv_set_context_attr(ibv_ctx, type, attr);
+}
+
+static int
+mlx5_glue_dv_init_obj(struct mlx5dv_obj *obj, uint64_t obj_type)
+{
+	return mlx5dv_init_obj(obj, obj_type);
+}
+
+const struct mlx5_glue *mlx5_glue = &(const struct mlx5_glue){
+	.fork_init = mlx5_glue_fork_init,
+	.alloc_pd = mlx5_glue_alloc_pd,
+	.dealloc_pd = mlx5_glue_dealloc_pd,
+	.get_device_list = mlx5_glue_get_device_list,
+	.free_device_list = mlx5_glue_free_device_list,
+	.open_device = mlx5_glue_open_device,
+	.close_device = mlx5_glue_close_device,
+	.get_device_name = mlx5_glue_get_device_name,
+	.query_device = mlx5_glue_query_device,
+	.query_device_ex = mlx5_glue_query_device_ex,
+	.query_port = mlx5_glue_query_port,
+	.create_comp_channel = mlx5_glue_create_comp_channel,
+	.destroy_comp_channel = mlx5_glue_destroy_comp_channel,
+	.create_cq = mlx5_glue_create_cq,
+	.destroy_cq = mlx5_glue_destroy_cq,
+	.get_cq_event = mlx5_glue_get_cq_event,
+	.ack_cq_events = mlx5_glue_ack_cq_events,
+	.create_rwq_ind_table = mlx5_glue_create_rwq_ind_table,
+	.destroy_rwq_ind_table = mlx5_glue_destroy_rwq_ind_table,
+	.create_wq = mlx5_glue_create_wq,
+	.destroy_wq = mlx5_glue_destroy_wq,
+	.modify_wq = mlx5_glue_modify_wq,
+	.create_flow = mlx5_glue_create_flow,
+	.destroy_flow = mlx5_glue_destroy_flow,
+	.create_qp = mlx5_glue_create_qp,
+	.create_qp_ex = mlx5_glue_create_qp_ex,
+	.destroy_qp = mlx5_glue_destroy_qp,
+	.modify_qp = mlx5_glue_modify_qp,
+	.reg_mr = mlx5_glue_reg_mr,
+	.dereg_mr = mlx5_glue_dereg_mr,
+	.create_counter_set = mlx5_glue_create_counter_set,
+	.destroy_counter_set = mlx5_glue_destroy_counter_set,
+	.ack_async_event = mlx5_glue_ack_async_event,
+	.get_async_event = mlx5_glue_get_async_event,
+	.port_state_str = mlx5_glue_port_state_str,
+	.cq_ex_to_cq = mlx5_glue_cq_ex_to_cq,
+	.dv_create_cq = mlx5_glue_dv_create_cq,
+	.dv_query_device = mlx5_glue_dv_query_device,
+	.dv_set_context_attr = mlx5_glue_dv_set_context_attr,
+	.dv_init_obj = mlx5_glue_dv_init_obj,
+};
diff --git a/drivers/net/mlx5/mlx5_glue.h b/drivers/net/mlx5/mlx5_glue.h
new file mode 100644
index 000000000..abf0878b1
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_glue.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox Technologies, Ltd.
+ */
+
+#ifndef MLX5_GLUE_H_
+#define MLX5_GLUE_H_
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+struct ibv_counter_set_init_attr {
+	int dummy;
+};
+struct ibv_counter_set {
+	int dummy;
+};
+#endif
+
+struct mlx5_glue {
+	int (*fork_init)(void);
+	struct ibv_pd *(*alloc_pd)(struct ibv_context *context);
+	int (*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_device **(*get_device_list)(int *num_devices);
+	void (*free_device_list)(struct ibv_device **list);
+	struct ibv_context *(*open_device)(struct ibv_device *device);
+	int (*close_device)(struct ibv_context *context);
+	const char *(*get_device_name)(struct ibv_device *device);
+	int (*query_port)(struct ibv_context *context, uint8_t port_num,
+			  struct ibv_port_attr *port_attr);
+	int (*query_device)(struct ibv_context *context,
+			    struct ibv_device_attr *device_attr);
+	int (*query_device_ex)(struct ibv_context *context,
+			       const struct ibv_query_device_ex_input *input,
+			       struct ibv_device_attr_ex *attr);
+	struct ibv_comp_channel *(*create_comp_channel)
+		(struct ibv_context *context);
+	int (*destroy_comp_channel)(struct ibv_comp_channel *channel);
+	struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe,
+				    void *cq_context,
+				    struct ibv_comp_channel *channel,
+				    int comp_vector);
+	int (*destroy_cq)(struct ibv_cq *cq);
+	int (*get_cq_event)(struct ibv_comp_channel *channel,
+			    struct ibv_cq **cq, void **cq_context);
+	void (*ack_cq_events)(struct ibv_cq *cq, unsigned int nevents);
+	struct ibv_rwq_ind_table *(*create_rwq_ind_table)
+		(struct ibv_context *context,
+		 struct ibv_rwq_ind_table_init_attr *init_attr);
+	int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table);
+	struct ibv_wq *(*create_wq)(struct ibv_context *context,
+				    struct ibv_wq_init_attr *wq_init_attr);
+	int (*destroy_wq)(struct ibv_wq *wq);
+	int (*modify_wq)(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr);
+	struct ibv_flow *(*create_flow)(struct ibv_qp *qp,
+					struct ibv_flow_attr *flow);
+	int (*destroy_flow)(struct ibv_flow *flow_id);
+	struct ibv_qp *(*create_qp)(struct ibv_pd *pd,
+				    struct ibv_qp_init_attr *qp_init_attr);
+	struct ibv_qp *(*create_qp_ex)
+		(struct ibv_context *context,
+		 struct ibv_qp_init_attr_ex *qp_init_attr_ex);
+	int (*destroy_qp)(struct ibv_qp *qp);
+	int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+			 int attr_mask);
+	struct ibv_mr *(*reg_mr)(struct ibv_pd *pd, void *addr,
+				 size_t length, int access);
+	int (*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_counter_set *(*create_counter_set)
+		(struct ibv_context *context,
+		 struct ibv_counter_set_init_attr *init_attr);
+	int (*destroy_counter_set)(struct ibv_counter_set *cs);
+	void (*ack_async_event)(struct ibv_async_event *event);
+	int (*get_async_event)(struct ibv_context *context,
+			       struct ibv_async_event *event);
+	const char *(*port_state_str)(enum ibv_port_state port_state);
+	struct ibv_cq *(*cq_ex_to_cq)(struct ibv_cq_ex *cq);
+	struct ibv_cq_ex *(*dv_create_cq)
+		(struct ibv_context *context,
+		 struct ibv_cq_init_attr_ex *cq_attr,
+		 struct mlx5dv_cq_init_attr *mlx5_cq_attr);
+	int (*dv_query_device)(struct ibv_context *ctx_in,
+			       struct mlx5dv_context *attrs_out);
+	int (*dv_set_context_attr)(struct ibv_context *ibv_ctx,
+				   enum mlx5dv_set_ctx_attr_type type,
+				   void *attr);
+	int (*dv_init_obj)(struct mlx5dv_obj *obj, uint64_t obj_type);
+};
+
+const struct mlx5_glue *mlx5_glue;
+
+#endif /* MLX5_GLUE_H_ */
diff --git a/drivers/net/mlx5/mlx5_mac.c b/drivers/net/mlx5/mlx5_mac.c
index a5e78ec8d..c42a59424 100644
--- a/drivers/net/mlx5/mlx5_mac.c
+++ b/drivers/net/mlx5/mlx5_mac.c
@@ -59,6 +59,7 @@
 #include "mlx5_utils.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_defs.h"
+#include "mlx5_glue.h"
 
 /**
  * Get MAC address by querying netdevice.
diff --git a/drivers/net/mlx5/mlx5_mr.c b/drivers/net/mlx5/mlx5_mr.c
index 2776dc700..61d476e51 100644
--- a/drivers/net/mlx5/mlx5_mr.c
+++ b/drivers/net/mlx5/mlx5_mr.c
@@ -46,6 +46,7 @@
 
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
+#include "mlx5_glue.h"
 
 struct mlx5_check_mempool_data {
 	int ret;
@@ -308,8 +309,8 @@ priv_mr_new(struct priv *priv, struct rte_mempool *mp)
 	DEBUG("mempool %p using start=%p end=%p size=%zu for MR",
 	      (void *)mp, (void *)start, (void *)end,
 	      (size_t)(end - start));
-	mr->mr = ibv_reg_mr(priv->pd, (void *)start, end - start,
-			    IBV_ACCESS_LOCAL_WRITE);
+	mr->mr = mlx5_glue->reg_mr(priv->pd, (void *)start, end - start,
+				   IBV_ACCESS_LOCAL_WRITE);
 	mr->mp = mp;
 	mr->lkey = rte_cpu_to_be_32(mr->mr->lkey);
 	rte_atomic32_inc(&mr->refcnt);
@@ -365,7 +366,7 @@ priv_mr_release(struct priv *priv, struct mlx5_mr *mr)
 	DEBUG("Memory Region %p refcnt: %d",
 	      (void *)mr, rte_atomic32_read(&mr->refcnt));
 	if (rte_atomic32_dec_and_test(&mr->refcnt)) {
-		claim_zero(ibv_dereg_mr(mr->mr));
+		claim_zero(mlx5_glue->dereg_mr(mr->mr));
 		LIST_REMOVE(mr, next);
 		rte_free(mr);
 		return 0;
diff --git a/drivers/net/mlx5/mlx5_rss.c b/drivers/net/mlx5/mlx5_rss.c
index 9e12b51fe..f842b1dcf 100644
--- a/drivers/net/mlx5/mlx5_rss.c
+++ b/drivers/net/mlx5/mlx5_rss.c
@@ -53,6 +53,7 @@
 #include "mlx5.h"
 #include "mlx5_defs.h"
 #include "mlx5_rxtx.h"
+#include "mlx5_glue.h"
 
 /**
  * DPDK callback to update the RSS hash configuration.
diff --git a/drivers/net/mlx5/mlx5_rxmode.c b/drivers/net/mlx5/mlx5_rxmode.c
index 897695855..151879c35 100644
--- a/drivers/net/mlx5/mlx5_rxmode.c
+++ b/drivers/net/mlx5/mlx5_rxmode.c
@@ -50,6 +50,7 @@
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_utils.h"
+#include "mlx5_glue.h"
 
 /**
  * DPDK callback to enable promiscuous mode.
diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c
index 0274ccf31..ada4dd5d9 100644
--- a/drivers/net/mlx5/mlx5_rxq.c
+++ b/drivers/net/mlx5/mlx5_rxq.c
@@ -63,6 +63,7 @@
 #include "mlx5_utils.h"
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
+#include "mlx5_glue.h"
 
 /* Default RSS hash key also used for ConnectX-3. */
 uint8_t rss_hash_default_key[] = {
@@ -601,13 +602,13 @@ mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id)
 		ret = EINVAL;
 		goto exit;
 	}
-	ret = ibv_get_cq_event(rxq_ibv->channel, &ev_cq, &ev_ctx);
+	ret = mlx5_glue->get_cq_event(rxq_ibv->channel, &ev_cq, &ev_ctx);
 	if (ret || ev_cq != rxq_ibv->cq) {
 		ret = EINVAL;
 		goto exit;
 	}
 	rxq_data->cq_arm_sn++;
-	ibv_ack_cq_events(rxq_ibv->cq, 1);
+	mlx5_glue->ack_cq_events(rxq_ibv->cq, 1);
 exit:
 	if (rxq_ibv)
 		mlx5_priv_rxq_ibv_release(priv, rxq_ibv);
@@ -675,7 +676,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		}
 	}
 	if (rxq_ctrl->irq) {
-		tmpl->channel = ibv_create_comp_channel(priv->ctx);
+		tmpl->channel = mlx5_glue->create_comp_channel(priv->ctx);
 		if (!tmpl->channel) {
 			ERROR("%p: Comp Channel creation failure",
 			      (void *)rxq_ctrl);
@@ -703,8 +704,9 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	} else if (config->cqe_comp && rxq_data->hw_timestamp) {
 		DEBUG("Rx CQE compression is disabled for HW timestamp");
 	}
-	tmpl->cq = ibv_cq_ex_to_cq(mlx5dv_create_cq(priv->ctx, &attr.cq.ibv,
-						    &attr.cq.mlx5));
+	tmpl->cq = mlx5_glue->cq_ex_to_cq
+		(mlx5_glue->dv_create_cq(priv->ctx, &attr.cq.ibv,
+					 &attr.cq.mlx5));
 	if (tmpl->cq == NULL) {
 		ERROR("%p: CQ creation failure", (void *)rxq_ctrl);
 		goto error;
@@ -740,7 +742,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		attr.wq.comp_mask |= IBV_WQ_INIT_ATTR_FLAGS;
 	}
 #endif
-	tmpl->wq = ibv_create_wq(priv->ctx, &attr.wq);
+	tmpl->wq = mlx5_glue->create_wq(priv->ctx, &attr.wq);
 	if (tmpl->wq == NULL) {
 		ERROR("%p: WQ creation failure", (void *)rxq_ctrl);
 		goto error;
@@ -764,7 +766,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		.attr_mask = IBV_WQ_ATTR_STATE,
 		.wq_state = IBV_WQS_RDY,
 	};
-	ret = ibv_modify_wq(tmpl->wq, &mod);
+	ret = mlx5_glue->modify_wq(tmpl->wq, &mod);
 	if (ret) {
 		ERROR("%p: WQ state to IBV_WQS_RDY failed",
 		      (void *)rxq_ctrl);
@@ -774,7 +776,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	obj.cq.out = &cq_info;
 	obj.rwq.in = tmpl->wq;
 	obj.rwq.out = &rwq;
-	ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_RWQ);
+	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_RWQ);
 	if (ret != 0)
 		goto error;
 	if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
@@ -824,11 +826,11 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	return tmpl;
 error:
 	if (tmpl->wq)
-		claim_zero(ibv_destroy_wq(tmpl->wq));
+		claim_zero(mlx5_glue->destroy_wq(tmpl->wq));
 	if (tmpl->cq)
-		claim_zero(ibv_destroy_cq(tmpl->cq));
+		claim_zero(mlx5_glue->destroy_cq(tmpl->cq));
 	if (tmpl->channel)
-		claim_zero(ibv_destroy_comp_channel(tmpl->channel));
+		claim_zero(mlx5_glue->destroy_comp_channel(tmpl->channel));
 	if (tmpl->mr)
 		priv_mr_release(priv, tmpl->mr);
 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
@@ -894,10 +896,11 @@ mlx5_priv_rxq_ibv_release(struct priv *priv, struct mlx5_rxq_ibv *rxq_ibv)
 	      (void *)rxq_ibv, rte_atomic32_read(&rxq_ibv->refcnt));
 	if (rte_atomic32_dec_and_test(&rxq_ibv->refcnt)) {
 		rxq_free_elts(rxq_ibv->rxq_ctrl);
-		claim_zero(ibv_destroy_wq(rxq_ibv->wq));
-		claim_zero(ibv_destroy_cq(rxq_ibv->cq));
+		claim_zero(mlx5_glue->destroy_wq(rxq_ibv->wq));
+		claim_zero(mlx5_glue->destroy_cq(rxq_ibv->cq));
 		if (rxq_ibv->channel)
-			claim_zero(ibv_destroy_comp_channel(rxq_ibv->channel));
+			claim_zero(mlx5_glue->destroy_comp_channel
+					(rxq_ibv->channel));
 		LIST_REMOVE(rxq_ibv, next);
 		rte_free(rxq_ibv);
 		return 0;
@@ -1225,13 +1228,13 @@ mlx5_priv_ind_table_ibv_new(struct priv *priv, uint16_t queues[],
 	/* Finalise indirection table. */
 	for (j = 0; i != (unsigned int)(1 << wq_n); ++i, ++j)
 		wq[i] = wq[j];
-	ind_tbl->ind_table = ibv_create_rwq_ind_table(
-		priv->ctx,
-		&(struct ibv_rwq_ind_table_init_attr){
+	ind_tbl->ind_table = mlx5_glue->create_rwq_ind_table
+		(priv->ctx,
+		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = wq_n,
 			.ind_tbl = wq,
 			.comp_mask = 0,
-		});
+		 });
 	if (!ind_tbl->ind_table)
 		goto error;
 	rte_atomic32_inc(&ind_tbl->refcnt);
@@ -1303,7 +1306,8 @@ mlx5_priv_ind_table_ibv_release(struct priv *priv,
 	DEBUG("%p: Indirection table %p: refcnt %d", (void *)priv,
 	      (void *)ind_tbl, rte_atomic32_read(&ind_tbl->refcnt));
 	if (rte_atomic32_dec_and_test(&ind_tbl->refcnt))
-		claim_zero(ibv_destroy_rwq_ind_table(ind_tbl->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table
+				(ind_tbl->ind_table));
 	for (i = 0; i != ind_tbl->queues_n; ++i)
 		claim_nonzero(mlx5_priv_rxq_release(priv, ind_tbl->queues[i]));
 	if (!rte_atomic32_read(&ind_tbl->refcnt)) {
@@ -1370,9 +1374,9 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 		ind_tbl = mlx5_priv_ind_table_ibv_new(priv, queues, queues_n);
 	if (!ind_tbl)
 		return NULL;
-	qp = ibv_create_qp_ex(
-		priv->ctx,
-		&(struct ibv_qp_init_attr_ex){
+	qp = mlx5_glue->create_qp_ex
+		(priv->ctx,
+		 &(struct ibv_qp_init_attr_ex){
 			.qp_type = IBV_QPT_RAW_PACKET,
 			.comp_mask =
 				IBV_QP_INIT_ATTR_PD |
@@ -1386,7 +1390,7 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 			},
 			.rwq_ind_tbl = ind_tbl->ind_table,
 			.pd = priv->pd,
-		});
+		 });
 	if (!qp)
 		goto error;
 	hrxq = rte_calloc(__func__, 1, sizeof(*hrxq) + rss_key_len, 0);
@@ -1405,7 +1409,7 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 error:
 	mlx5_priv_ind_table_ibv_release(priv, ind_tbl);
 	if (qp)
-		claim_zero(ibv_destroy_qp(qp));
+		claim_zero(mlx5_glue->destroy_qp(qp));
 	return NULL;
 }
 
@@ -1473,7 +1477,7 @@ mlx5_priv_hrxq_release(struct priv *priv, struct mlx5_hrxq *hrxq)
 	DEBUG("%p: Hash Rx queue %p: refcnt %d", (void *)priv,
 	      (void *)hrxq, rte_atomic32_read(&hrxq->refcnt));
 	if (rte_atomic32_dec_and_test(&hrxq->refcnt)) {
-		claim_zero(ibv_destroy_qp(hrxq->qp));
+		claim_zero(mlx5_glue->destroy_qp(hrxq->qp));
 		mlx5_priv_ind_table_ibv_release(priv, hrxq->ind_table);
 		LIST_REMOVE(hrxq, next);
 		rte_free(hrxq);
diff --git a/drivers/net/mlx5/mlx5_rxtx.c b/drivers/net/mlx5/mlx5_rxtx.c
index 3b8f71c28..345ab5f48 100644
--- a/drivers/net/mlx5/mlx5_rxtx.c
+++ b/drivers/net/mlx5/mlx5_rxtx.c
@@ -60,6 +60,7 @@
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
 #include "mlx5_prm.h"
+#include "mlx5_glue.h"
 
 static __rte_always_inline uint32_t
 rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe);
diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h
index 2eb2f0506..8d5759c5d 100644
--- a/drivers/net/mlx5/mlx5_rxtx.h
+++ b/drivers/net/mlx5/mlx5_rxtx.h
@@ -60,6 +60,7 @@
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
 #include "mlx5_prm.h"
+#include "mlx5_glue.h"
 
 struct mlx5_rxq_stats {
 	unsigned int idx; /**< Mapping index. */
diff --git a/drivers/net/mlx5/mlx5_rxtx_vec.c b/drivers/net/mlx5/mlx5_rxtx_vec.c
index 142c786d5..6fb10b90c 100644
--- a/drivers/net/mlx5/mlx5_rxtx_vec.c
+++ b/drivers/net/mlx5/mlx5_rxtx_vec.c
@@ -58,6 +58,7 @@
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
 #include "mlx5_prm.h"
+#include "mlx5_glue.h"
 
 #if defined RTE_ARCH_X86_64
 #include "mlx5_rxtx_vec_sse.h"
diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c
index 18321c3e3..9b21ec609 100644
--- a/drivers/net/mlx5/mlx5_txq.c
+++ b/drivers/net/mlx5/mlx5_txq.c
@@ -59,6 +59,7 @@
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
 
 /**
  * Allocate TX queue elements.
@@ -411,7 +412,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		((desc / MLX5_TX_COMP_THRESH) - 1) : 1;
 	if (is_empw_burst_func(tx_pkt_burst))
 		cqe_n += MLX5_TX_COMP_THRESH_INLINE_DIV;
-	tmpl.cq = ibv_create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
+	tmpl.cq = mlx5_glue->create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
 	if (tmpl.cq == NULL) {
 		ERROR("%p: CQ creation failure", (void *)txq_ctrl);
 		goto error;
@@ -452,7 +453,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		attr.init.max_tso_header = txq_ctrl->max_tso_header;
 		attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
 	}
-	tmpl.qp = ibv_create_qp_ex(priv->ctx, &attr.init);
+	tmpl.qp = mlx5_glue->create_qp_ex(priv->ctx, &attr.init);
 	if (tmpl.qp == NULL) {
 		ERROR("%p: QP creation failure", (void *)txq_ctrl);
 		goto error;
@@ -463,7 +464,8 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		/* Primary port number. */
 		.port_num = priv->port
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, (IBV_QP_STATE | IBV_QP_PORT));
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod,
+				   (IBV_QP_STATE | IBV_QP_PORT));
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_INIT failed", (void *)txq_ctrl);
 		goto error;
@@ -471,13 +473,13 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	attr.mod = (struct ibv_qp_attr){
 		.qp_state = IBV_QPS_RTR
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_RTR failed", (void *)txq_ctrl);
 		goto error;
 	}
 	attr.mod.qp_state = IBV_QPS_RTS;
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_RTS failed", (void *)txq_ctrl);
 		goto error;
@@ -492,7 +494,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	obj.cq.out = &cq_info;
 	obj.qp.in = tmpl.qp;
 	obj.qp.out = &qp;
-	ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
+	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
 	if (ret != 0)
 		goto error;
 	if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
@@ -532,9 +534,9 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	return txq_ibv;
 error:
 	if (tmpl.cq)
-		claim_zero(ibv_destroy_cq(tmpl.cq));
+		claim_zero(mlx5_glue->destroy_cq(tmpl.cq));
 	if (tmpl.qp)
-		claim_zero(ibv_destroy_qp(tmpl.qp));
+		claim_zero(mlx5_glue->destroy_qp(tmpl.qp));
 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
 	return NULL;
 }
@@ -588,8 +590,8 @@ mlx5_priv_txq_ibv_release(struct priv *priv, struct mlx5_txq_ibv *txq_ibv)
 	DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
 	      (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
 	if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
-		claim_zero(ibv_destroy_qp(txq_ibv->qp));
-		claim_zero(ibv_destroy_cq(txq_ibv->cq));
+		claim_zero(mlx5_glue->destroy_qp(txq_ibv->qp));
+		claim_zero(mlx5_glue->destroy_cq(txq_ibv->cq));
 		LIST_REMOVE(txq_ibv, next);
 		rte_free(txq_ibv);
 		return 0;
diff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c
index d51dbe941..08963f2e9 100644
--- a/drivers/net/mlx5/mlx5_vlan.c
+++ b/drivers/net/mlx5/mlx5_vlan.c
@@ -138,7 +138,7 @@ priv_vlan_strip_queue_set(struct priv *priv, uint16_t idx, int on)
 		.flags = vlan_offloads,
 	};
 
-	err = ibv_modify_wq(rxq_ctrl->ibv->wq, &mod);
+	err = mlx5_glue->modify_wq(rxq_ctrl->ibv->wq, &mod);
 	if (err) {
 		ERROR("%p: failed to modified stripping mode: %s",
 		      (void *)priv, strerror(err));
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v1 4/4] net/mlx5: spawn rdma-core dependency plug-in
  2018-01-24 23:24 [PATCH v1 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
                   ` (2 preceding siblings ...)
  2018-01-24 23:25 ` [PATCH v1 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
@ 2018-01-24 23:25 ` Adrien Mazarguil
  2018-01-26 14:18 ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  4 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-24 23:25 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

When mlx5 is not compiled directly as an independent shared object (e.g.
CONFIG_RTE_BUILD_SHARED_LIB not enabled for performance reasons), DPDK
applications inherit its dependencies on libibverbs and libmlx5 through
rte.app.mk.

This is an issue both when DPDK is delivered as a binary package (Linux
distributions) and for end users because rdma-core then propagates as a
mandatory dependency for everything.

Application writers relying on binary DPDK packages are not necessarily
aware of this fact and may end up delivering packages with broken
dependencies.

This patch therefore introduces an intermediate internal plug-in
hard-linked with rdma-core (to preserve symbol versioning) loaded by the
PMD through dlopen(), so that a missing rdma-core does not cause unresolved
symbols, allowing applications to start normally.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 drivers/net/mlx5/Makefile | 40 +++++++++++++++++++++
 drivers/net/mlx5/mlx5.c   | 79 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index bdec30692..35525f6d0 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -53,7 +53,11 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c
+ifneq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue_lib.c
+else
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
+endif
 
 # Basic CFLAGS.
 CFLAGS += -O3
@@ -65,7 +69,12 @@ CFLAGS += -D_DEFAULT_SOURCE
 CFLAGS += -D_XOPEN_SOURCE=600
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -Wno-strict-prototypes
+ifneq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+CFLAGS_mlx5_glue.o += -fPIC
+LDLIBS += -ldl
+else
 LDLIBS += -libverbs -lmlx5
+endif
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
@@ -158,7 +167,38 @@ mlx5_autoconf.h: mlx5_autoconf.h.new
 
 $(SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD):.c=.o): mlx5_autoconf.h
 
+# Generate dependency plug-in for rdma-core when the PMD cannot be linked
+# directly, so that applications do not inherit this dependency.
+
+ifneq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+
+mlx5_glue_lib.c: mlx5_glue_lib.so
+	$Q printf '#include <stddef.h>\n' > $@
+	$Q printf '#include <stdint.h>\n\n' >> $@
+	$Q printf 'const uint8_t mlx5_glue_lib[][16] = {\n' >> $@
+	$Q od -vt x1 $< | \
+	sed -ne '/^[[:xdigit:]]\{1,\}/{' \
+		-e 's///;' \
+		-e '/^$$/d; ' \
+		-e 's/[[:space:]]*$$//;' \
+		-e 's/[[:space:]]\{1,\}/\\x/g;' \
+		-e 's/^/	"/;' \
+		-e 's/$$/",/;' \
+		-e 'p;' \
+		-e '}' >> $@
+	$Q printf '};\n\n' >> $@
+	$Q printf 'const size_t mlx5_glue_lib_size = %u;' $$(wc -c < $<) >> $@
+
+mlx5_glue_lib.so: mlx5_glue.o
+	$Q $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) \
+		-s -shared -o $@ $< -libverbs -lmlx5
+
+mlx5_glue.o: mlx5_autoconf.h
+
+endif
+
 clean_mlx5: FORCE
 	$Q rm -f -- mlx5_autoconf.h mlx5_autoconf.h.new
+	$Q rm -f -- mlx5_glue.o mlx5_glue_lib.*
 
 clean: clean_mlx5
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index b36cc611f..7ef724585 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -35,6 +35,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>
+#include <dlfcn.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -56,6 +57,7 @@
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
 #include <rte_common.h>
+#include <rte_config.h>
 #include <rte_kvargs.h>
 
 #include "mlx5.h"
@@ -966,6 +968,78 @@ static struct rte_pci_driver mlx5_driver = {
 	.drv_flags = RTE_PCI_DRV_INTR_LSC | RTE_PCI_DRV_INTR_RMV,
 };
 
+#ifndef RTE_BUILD_SHARED_LIB
+
+extern const uint8_t mlx5_glue_lib[][16];
+extern const size_t mlx5_glue_lib_size;
+
+/**
+ * Initialization routine for run-time dependency on rdma-core.
+ */
+static int
+mlx5_glue_init(void)
+{
+	char file[] = "/tmp/" MLX5_DRIVER_NAME "_XXXXXX";
+	int fd = mkstemp(file);
+	size_t off = 0;
+	void *handle = NULL;
+	void **sym;
+	const char *dlmsg;
+
+	if (fd == -1) {
+		rte_errno = errno;
+		goto glue_error;
+	}
+	while (off != mlx5_glue_lib_size) {
+		ssize_t ret;
+
+		ret = write(fd, (const uint8_t *)mlx5_glue_lib + off,
+			    mlx5_glue_lib_size - off);
+		if (ret == -1) {
+			if (errno != EINTR) {
+				rte_errno = errno;
+				goto glue_error;
+			}
+			ret = 0;
+		}
+		off += ret;
+	}
+	close(fd);
+	fd = -1;
+	handle = dlopen(file, RTLD_LAZY);
+	unlink(file);
+	if (!handle) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot load glue library: %s", dlmsg);
+		goto glue_error;
+	}
+	sym = dlsym(handle, "mlx5_glue");
+	if (!sym || !*sym) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot resolve glue symbol: %s", dlmsg);
+		goto glue_error;
+	}
+	mlx5_glue = *sym;
+	return 0;
+glue_error:
+	if (handle)
+		dlclose(handle);
+	if (fd != -1) {
+		close(fd);
+		unlink(file);
+	}
+	ERROR("cannot initialize PMD due to missing run-time"
+	      " dependency on rdma-core libraries (libibverbs,"
+	      " libmlx5)");
+	return -rte_errno;
+}
+
+#endif
+
 /**
  * Driver initialization routine.
  */
@@ -985,6 +1059,11 @@ rte_mlx5_pmd_init(void)
 	/* Match the size of Rx completion entry to the size of a cacheline. */
 	if (RTE_CACHE_LINE_SIZE == 128)
 		setenv("MLX5_CQE_SIZE", "128", 0);
+#ifndef RTE_BUILD_SHARED_LIB
+	if (mlx5_glue_init())
+		return;
+	assert(mlx5_glue);
+#endif
 	mlx5_glue->fork_init();
 	rte_pci_register(&mlx5_driver);
 }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v1 1/4] net/mlx4: move rdma-core calls to separate file
  2018-01-24 23:25 ` [PATCH v1 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
@ 2018-01-24 23:58   ` Stephen Hemminger
  2018-01-25 11:31     ` Adrien Mazarguil
  0 siblings, 1 reply; 31+ messages in thread
From: Stephen Hemminger @ 2018-01-24 23:58 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: Shahaf Shuler, Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

On Thu, 25 Jan 2018 00:25:00 +0100
Adrien Mazarguil <adrien.mazarguil@6wind.com> wrote:

> +const struct mlx4_glue *mlx4_glue = &(const struct mlx4_glue){
> +	.fork_init = mlx4_glue_fork_init,
> +	.get_async_event = mlx4_glue_get_async_event,

The cast should not be necessary here.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v1 1/4] net/mlx4: move rdma-core calls to separate file
  2018-01-24 23:58   ` Stephen Hemminger
@ 2018-01-25 11:31     ` Adrien Mazarguil
  0 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-25 11:31 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Shahaf Shuler, Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

On Wed, Jan 24, 2018 at 03:58:57PM -0800, Stephen Hemminger wrote:
> On Thu, 25 Jan 2018 00:25:00 +0100
> Adrien Mazarguil <adrien.mazarguil@6wind.com> wrote:
> 
> > +const struct mlx4_glue *mlx4_glue = &(const struct mlx4_glue){
> > +	.fork_init = mlx4_glue_fork_init,
> > +	.get_async_event = mlx4_glue_get_async_event,
> 
> The cast should not be necessary here.

It's not a mere cast but a compound literal. The mlx4_glue symbol represents
a pointer to this structure, not the structure itself. This syntax is
equivalent to:

 static const struct mlx4_glue mlx4_glue_internal = {
    ...
 };

 const struct mlx4_glue *mlx4_glue = &mlx4_glue_internal;

The reason I chose to expose a pointer instead of that structure directly is
seamless transition to dlsym() in the next patch, otherwise all
mlx4_glue->foo() need to be first written mlx4_glue.foo() and then modified
as mlx4_glue->foo().

-- 
Adrien Mazarguil
6WIND

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v1 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-24 23:25 ` [PATCH v1 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-26 10:06   ` Thomas Monjalon
  0 siblings, 0 replies; 31+ messages in thread
From: Thomas Monjalon @ 2018-01-26 10:06 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, Shahaf Shuler, Nelio Laranjeiro, Marcelo Ricardo Leitner

25/01/2018 00:25, Adrien Mazarguil:
> --- a/drivers/net/mlx4/Makefile
> +++ b/drivers/net/mlx4/Makefile
> @@ -38,7 +38,11 @@ LIB = librte_pmd_mlx4.a
>  SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4.c
>  SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_ethdev.c
>  SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_flow.c
> +ifneq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
> +SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue_lib.c
> +else

Using this dlopen mode to manage the dependency requirement
should be a decision of the user/packager.
Please introduce a new option which allows to enable/disable this mode,
unrelated to the DPDK compilation mode being shared or static.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time
  2018-01-24 23:24 [PATCH v1 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
                   ` (3 preceding siblings ...)
  2018-01-24 23:25 ` [PATCH v1 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-26 14:18 ` Adrien Mazarguil
  2018-01-26 14:18   ` [PATCH v2 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
                     ` (5 more replies)
  4 siblings, 6 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-26 14:18 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

A problem encountered with Mellanox PMDs and frequently reported by DPDK
application developers and Linux distribution package maintainers is their
dependency on rdma-core components, namely libibverbs, libmlx4, and libmlx5.

For best performance in applications, DPDK is normally built as a collection
of library archives (.a files), whose external dependencies are inherited
through rte.app.mk during link.

When these PMDs are built-in, any binary DPDK package, whether DPDK itself
or derived applications, always have to pull rdma-core. This dependency is
not obvious and may be missed during the packaging of any intermediate layer
between DPDK itself and the end application.

While still required during compilation, this series trades this hard
dependency for an optional one, dynamically loaded at run-time through
dlopen().

It supersedes Shachar's previous work on the same topic [1] using a
different approach in order to preserve symbol versioning and address
the remaining issues.

[1] http://dpdk.org/ml/archives/dev/2017-December/085090.html

v2 changes:

- Rebased on dpdk-next-net-mlx.
- Rely on CONFIG_RTE_LIBRTE_MLX[45]_DLOPEN_DEPS instead of
  CONFIG_RTE_BUILD_SHARED_LIB to enable this mode, so it can be overridden
  if necessary.
- Fixed -lmlx5 -libibverbs leftovers in rte.app.mk.
- Minor fixes for indentation and unnecessary includes in mlx5.

Adrien Mazarguil (3):
  net/mlx4: move rdma-core calls to separate file
  net/mlx4: spawn rdma-core dependency plug-in
  net/mlx5: spawn rdma-core dependency plug-in

Nelio Laranjeiro (1):
  net/mlx5: move rdma-core calls to separate file

 config/common_base             |   2 +
 doc/guides/nics/mlx4.rst       |  13 ++
 doc/guides/nics/mlx5.rst       |  13 ++
 drivers/net/mlx4/Makefile      |  42 +++++
 drivers/net/mlx4/mlx4.c        | 115 +++++++++++--
 drivers/net/mlx4/mlx4_ethdev.c |   3 +-
 drivers/net/mlx4/mlx4_flow.c   |  32 ++--
 drivers/net/mlx4/mlx4_glue.c   | 275 ++++++++++++++++++++++++++++++
 drivers/net/mlx4/mlx4_glue.h   |  80 +++++++++
 drivers/net/mlx4/mlx4_intr.c   |  10 +-
 drivers/net/mlx4/mlx4_mr.c     |   7 +-
 drivers/net/mlx4/mlx4_rxq.c    |  53 +++---
 drivers/net/mlx4/mlx4_txq.c    |  17 +-
 drivers/net/mlx5/Makefile      |  42 +++++
 drivers/net/mlx5/mlx5.c        | 123 +++++++++++---
 drivers/net/mlx5/mlx5_ethdev.c |   7 +-
 drivers/net/mlx5/mlx5_flow.c   |  92 +++++------
 drivers/net/mlx5/mlx5_glue.c   | 321 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h   |  99 +++++++++++
 drivers/net/mlx5/mlx5_mr.c     |   7 +-
 drivers/net/mlx5/mlx5_rxq.c    |  54 +++---
 drivers/net/mlx5/mlx5_txq.c    |  22 +--
 drivers/net/mlx5/mlx5_vlan.c   |  13 +-
 mk/rte.app.mk                  |   8 +
 24 files changed, 1265 insertions(+), 185 deletions(-)
 create mode 100644 drivers/net/mlx4/mlx4_glue.c
 create mode 100644 drivers/net/mlx4/mlx4_glue.h
 create mode 100644 drivers/net/mlx5/mlx5_glue.c
 create mode 100644 drivers/net/mlx5/mlx5_glue.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v2 1/4] net/mlx4: move rdma-core calls to separate file
  2018-01-26 14:18 ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
@ 2018-01-26 14:18   ` Adrien Mazarguil
  2018-01-26 14:19   ` [PATCH v2 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-26 14:18 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

This lays the groundwork for externalizing rdma-core as an optional
run-time dependency instead of a mandatory one.

No functional change.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 drivers/net/mlx4/Makefile      |   1 +
 drivers/net/mlx4/mlx4.c        |  35 ++---
 drivers/net/mlx4/mlx4_ethdev.c |   3 +-
 drivers/net/mlx4/mlx4_flow.c   |  32 +++--
 drivers/net/mlx4/mlx4_glue.c   | 275 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx4/mlx4_glue.h   |  80 +++++++++++
 drivers/net/mlx4/mlx4_intr.c   |  10 +-
 drivers/net/mlx4/mlx4_mr.c     |   7 +-
 drivers/net/mlx4/mlx4_rxq.c    |  53 +++----
 drivers/net/mlx4/mlx4_txq.c    |  17 +--
 10 files changed, 440 insertions(+), 73 deletions(-)

diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1f95e0df9..1d33c38ed 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -38,6 +38,7 @@ LIB = librte_pmd_mlx4.a
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_intr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxq.c
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 2a721e7e2..0fd9a999c 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -67,6 +67,7 @@
 #include <rte_mbuf.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -218,8 +219,8 @@ mlx4_dev_close(struct rte_eth_dev *dev)
 		mlx4_tx_queue_release(dev->data->tx_queues[i]);
 	if (priv->pd != NULL) {
 		assert(priv->ctx != NULL);
-		claim_zero(ibv_dealloc_pd(priv->pd));
-		claim_zero(ibv_close_device(priv->ctx));
+		claim_zero(mlx4_glue->dealloc_pd(priv->pd));
+		claim_zero(mlx4_glue->close_device(priv->ctx));
 	} else
 		assert(priv->ctx == NULL);
 	mlx4_intr_uninstall(priv);
@@ -436,7 +437,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 	(void)pci_drv;
 	assert(pci_drv == &mlx4_driver);
-	list = ibv_get_device_list(&i);
+	list = mlx4_glue->get_device_list(&i);
 	if (list == NULL) {
 		rte_errno = errno;
 		assert(rte_errno);
@@ -465,12 +466,12 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		      PCI_DEVICE_ID_MELLANOX_CONNECTX3VF);
 		INFO("PCI information matches, using device \"%s\" (VF: %s)",
 		     list[i]->name, (vf ? "true" : "false"));
-		attr_ctx = ibv_open_device(list[i]);
+		attr_ctx = mlx4_glue->open_device(list[i]);
 		err = errno;
 		break;
 	}
 	if (attr_ctx == NULL) {
-		ibv_free_device_list(list);
+		mlx4_glue->free_device_list(list);
 		switch (err) {
 		case 0:
 			rte_errno = ENODEV;
@@ -487,7 +488,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	}
 	ibv_dev = list[i];
 	DEBUG("device opened");
-	if (ibv_query_device(attr_ctx, &device_attr)) {
+	if (mlx4_glue->query_device(attr_ctx, &device_attr)) {
 		rte_errno = ENODEV;
 		goto error;
 	}
@@ -502,7 +503,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	if (!conf.ports.enabled)
 		conf.ports.enabled = conf.ports.present;
 	/* Retrieve extended device attributes. */
-	if (ibv_query_device_ex(attr_ctx, NULL, &device_attr_ex)) {
+	if (mlx4_glue->query_device_ex(attr_ctx, NULL, &device_attr_ex)) {
 		rte_errno = ENODEV;
 		goto error;
 	}
@@ -520,13 +521,13 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		if (!(conf.ports.enabled & (1 << i)))
 			continue;
 		DEBUG("using port %u", port);
-		ctx = ibv_open_device(ibv_dev);
+		ctx = mlx4_glue->open_device(ibv_dev);
 		if (ctx == NULL) {
 			rte_errno = ENODEV;
 			goto port_error;
 		}
 		/* Check port status. */
-		err = ibv_query_port(ctx, port, &port_attr);
+		err = mlx4_glue->query_port(ctx, port, &port_attr);
 		if (err) {
 			rte_errno = err;
 			ERROR("port query failed: %s", strerror(rte_errno));
@@ -540,7 +541,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		}
 		if (port_attr.state != IBV_PORT_ACTIVE)
 			DEBUG("port %d is not active: \"%s\" (%d)",
-			      port, ibv_port_state_str(port_attr.state),
+			      port, mlx4_glue->port_state_str(port_attr.state),
 			      port_attr.state);
 		/* Make asynchronous FD non-blocking to handle interrupts. */
 		if (mlx4_fd_set_non_blocking(ctx->async_fd) < 0) {
@@ -549,7 +550,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			goto port_error;
 		}
 		/* Allocate protection domain. */
-		pd = ibv_alloc_pd(ctx);
+		pd = mlx4_glue->alloc_pd(ctx);
 		if (pd == NULL) {
 			rte_errno = ENOMEM;
 			ERROR("PD allocation failure");
@@ -628,7 +629,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			char name[RTE_ETH_NAME_MAX_LEN];
 
 			snprintf(name, sizeof(name), "%s port %u",
-				 ibv_get_device_name(ibv_dev), port);
+				 mlx4_glue->get_device_name(ibv_dev), port);
 			eth_dev = rte_eth_dev_allocate(name);
 		}
 		if (eth_dev == NULL) {
@@ -671,9 +672,9 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 port_error:
 		rte_free(priv);
 		if (pd)
-			claim_zero(ibv_dealloc_pd(pd));
+			claim_zero(mlx4_glue->dealloc_pd(pd));
 		if (ctx)
-			claim_zero(ibv_close_device(ctx));
+			claim_zero(mlx4_glue->close_device(ctx));
 		if (eth_dev)
 			rte_eth_dev_release_port(eth_dev);
 		break;
@@ -688,9 +689,9 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	 */
 error:
 	if (attr_ctx)
-		claim_zero(ibv_close_device(attr_ctx));
+		claim_zero(mlx4_glue->close_device(attr_ctx));
 	if (list)
-		ibv_free_device_list(list);
+		mlx4_glue->free_device_list(list);
 	assert(rte_errno >= 0);
 	return -rte_errno;
 }
@@ -743,7 +744,7 @@ rte_mlx4_pmd_init(void)
 	 * using this PMD, which is not supported in forked processes.
 	 */
 	setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
-	ibv_fork_init();
+	mlx4_glue->fork_init();
 	rte_pci_register(&mlx4_driver);
 }
 
diff --git a/drivers/net/mlx4/mlx4_ethdev.c b/drivers/net/mlx4/mlx4_ethdev.c
index ca5fadc72..d1d940dc7 100644
--- a/drivers/net/mlx4/mlx4_ethdev.c
+++ b/drivers/net/mlx4/mlx4_ethdev.c
@@ -70,6 +70,7 @@
 
 #include "mlx4.h"
 #include "mlx4_flow.h"
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -1068,7 +1069,7 @@ mlx4_is_removed(struct rte_eth_dev *dev)
 	struct ibv_device_attr device_attr;
 	struct priv *priv = dev->data->dev_private;
 
-	if (ibv_query_device(priv->ctx, &device_attr) == EIO)
+	if (mlx4_glue->query_device(priv->ctx, &device_attr) == EIO)
 		return 1;
 	return 0;
 }
diff --git a/drivers/net/mlx4/mlx4_flow.c b/drivers/net/mlx4/mlx4_flow.c
index fb84060db..7f1f7e852 100644
--- a/drivers/net/mlx4/mlx4_flow.c
+++ b/drivers/net/mlx4/mlx4_flow.c
@@ -65,6 +65,7 @@
 
 /* PMD headers. */
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -922,24 +923,25 @@ mlx4_drop_get(struct priv *priv)
 		.priv = priv,
 		.refcnt = 1,
 	};
-	drop->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+	drop->cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 	if (!drop->cq)
 		goto error;
-	drop->qp = ibv_create_qp(priv->pd,
-				 &(struct ibv_qp_init_attr){
-					.send_cq = drop->cq,
-					.recv_cq = drop->cq,
-					.qp_type = IBV_QPT_RAW_PACKET,
-				 });
+	drop->qp = mlx4_glue->create_qp
+		(priv->pd,
+		 &(struct ibv_qp_init_attr){
+			.send_cq = drop->cq,
+			.recv_cq = drop->cq,
+			.qp_type = IBV_QPT_RAW_PACKET,
+		 });
 	if (!drop->qp)
 		goto error;
 	priv->drop = drop;
 	return drop;
 error:
 	if (drop->qp)
-		claim_zero(ibv_destroy_qp(drop->qp));
+		claim_zero(mlx4_glue->destroy_qp(drop->qp));
 	if (drop->cq)
-		claim_zero(ibv_destroy_cq(drop->cq));
+		claim_zero(mlx4_glue->destroy_cq(drop->cq));
 	if (drop)
 		rte_free(drop);
 	rte_errno = ENOMEM;
@@ -959,8 +961,8 @@ mlx4_drop_put(struct mlx4_drop *drop)
 	if (--drop->refcnt)
 		return;
 	drop->priv->drop = NULL;
-	claim_zero(ibv_destroy_qp(drop->qp));
-	claim_zero(ibv_destroy_cq(drop->cq));
+	claim_zero(mlx4_glue->destroy_qp(drop->qp));
+	claim_zero(mlx4_glue->destroy_cq(drop->cq));
 	rte_free(drop);
 }
 
@@ -992,7 +994,7 @@ mlx4_flow_toggle(struct priv *priv,
 	if (!enable) {
 		if (!flow->ibv_flow)
 			return 0;
-		claim_zero(ibv_destroy_flow(flow->ibv_flow));
+		claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 		flow->ibv_flow = NULL;
 		if (flow->drop)
 			mlx4_drop_put(priv->drop);
@@ -1005,7 +1007,7 @@ mlx4_flow_toggle(struct priv *priv,
 	    !priv->isolated &&
 	    flow->ibv_attr->priority == MLX4_FLOW_PRIORITY_LAST) {
 		if (flow->ibv_flow) {
-			claim_zero(ibv_destroy_flow(flow->ibv_flow));
+			claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 			flow->ibv_flow = NULL;
 			if (flow->drop)
 				mlx4_drop_put(priv->drop);
@@ -1035,7 +1037,7 @@ mlx4_flow_toggle(struct priv *priv,
 			if (missing ^ !flow->drop)
 				return 0;
 			/* Verbs flow needs updating. */
-			claim_zero(ibv_destroy_flow(flow->ibv_flow));
+			claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 			flow->ibv_flow = NULL;
 			if (flow->drop)
 				mlx4_drop_put(priv->drop);
@@ -1067,7 +1069,7 @@ mlx4_flow_toggle(struct priv *priv,
 	assert(qp);
 	if (flow->ibv_flow)
 		return 0;
-	flow->ibv_flow = ibv_create_flow(qp, flow->ibv_attr);
+	flow->ibv_flow = mlx4_glue->create_flow(qp, flow->ibv_attr);
 	if (flow->ibv_flow)
 		return 0;
 	if (flow->drop)
diff --git a/drivers/net/mlx4/mlx4_glue.c b/drivers/net/mlx4/mlx4_glue.c
new file mode 100644
index 000000000..30797bd2b
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_glue.c
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox
+ */
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx4dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#include "mlx4_glue.h"
+
+static int
+mlx4_glue_fork_init(void)
+{
+	return ibv_fork_init();
+}
+
+static int
+mlx4_glue_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
+{
+	return ibv_get_async_event(context, event);
+}
+
+static void
+mlx4_glue_ack_async_event(struct ibv_async_event *event)
+{
+	ibv_ack_async_event(event);
+}
+
+static struct ibv_pd *
+mlx4_glue_alloc_pd(struct ibv_context *context)
+{
+	return ibv_alloc_pd(context);
+}
+
+static int
+mlx4_glue_dealloc_pd(struct ibv_pd *pd)
+{
+	return ibv_dealloc_pd(pd);
+}
+
+static struct ibv_device **
+mlx4_glue_get_device_list(int *num_devices)
+{
+	return ibv_get_device_list(num_devices);
+}
+
+static void
+mlx4_glue_free_device_list(struct ibv_device **list)
+{
+	ibv_free_device_list(list);
+}
+
+static struct ibv_context *
+mlx4_glue_open_device(struct ibv_device *device)
+{
+	return ibv_open_device(device);
+}
+
+static int
+mlx4_glue_close_device(struct ibv_context *context)
+{
+	return ibv_close_device(context);
+}
+
+static const char *
+mlx4_glue_get_device_name(struct ibv_device *device)
+{
+	return ibv_get_device_name(device);
+}
+
+static int
+mlx4_glue_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context, device_attr);
+}
+
+static int
+mlx4_glue_query_device_ex(struct ibv_context *context,
+			  const struct ibv_query_device_ex_input *input,
+			  struct ibv_device_attr_ex *attr)
+{
+	return ibv_query_device_ex(context, input, attr);
+}
+
+static int
+mlx4_glue_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context, port_num, port_attr);
+}
+
+static const char *
+mlx4_glue_port_state_str(enum ibv_port_state port_state)
+{
+	return ibv_port_state_str(port_state);
+}
+
+static struct ibv_comp_channel *
+mlx4_glue_create_comp_channel(struct ibv_context *context)
+{
+	return ibv_create_comp_channel(context);
+}
+
+static int
+mlx4_glue_destroy_comp_channel(struct ibv_comp_channel *channel)
+{
+	return ibv_destroy_comp_channel(channel);
+}
+
+static struct ibv_cq *
+mlx4_glue_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+		    struct ibv_comp_channel *channel, int comp_vector)
+{
+	return ibv_create_cq(context, cqe, cq_context, channel, comp_vector);
+}
+
+static int
+mlx4_glue_destroy_cq(struct ibv_cq *cq)
+{
+	return ibv_destroy_cq(cq);
+}
+
+static int
+mlx4_glue_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
+		       void **cq_context)
+{
+	return ibv_get_cq_event(channel, cq, cq_context);
+}
+
+static void
+mlx4_glue_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq, nevents);
+}
+
+static struct ibv_flow *
+mlx4_glue_create_flow(struct ibv_qp *qp, struct ibv_flow_attr *flow)
+{
+	return ibv_create_flow(qp, flow);
+}
+
+static int
+mlx4_glue_destroy_flow(struct ibv_flow *flow_id)
+{
+	return ibv_destroy_flow(flow_id);
+}
+
+static struct ibv_qp *
+mlx4_glue_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
+{
+	return ibv_create_qp(pd, qp_init_attr);
+}
+
+static struct ibv_qp *
+mlx4_glue_create_qp_ex(struct ibv_context *context,
+		       struct ibv_qp_init_attr_ex *qp_init_attr_ex)
+{
+	return ibv_create_qp_ex(context, qp_init_attr_ex);
+}
+
+static int
+mlx4_glue_destroy_qp(struct ibv_qp *qp)
+{
+	return ibv_destroy_qp(qp);
+}
+
+static int
+mlx4_glue_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
+{
+	return ibv_modify_qp(qp, attr, attr_mask);
+}
+
+static struct ibv_mr *
+mlx4_glue_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access)
+{
+	return ibv_reg_mr(pd, addr, length, access);
+}
+
+static int
+mlx4_glue_dereg_mr(struct ibv_mr *mr)
+{
+	return ibv_dereg_mr(mr);
+}
+
+static struct ibv_rwq_ind_table *
+mlx4_glue_create_rwq_ind_table(struct ibv_context *context,
+			       struct ibv_rwq_ind_table_init_attr *init_attr)
+{
+	return ibv_create_rwq_ind_table(context, init_attr);
+}
+
+static int
+mlx4_glue_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table)
+{
+	return ibv_destroy_rwq_ind_table(rwq_ind_table);
+}
+
+static struct ibv_wq *
+mlx4_glue_create_wq(struct ibv_context *context,
+		    struct ibv_wq_init_attr *wq_init_attr)
+{
+	return ibv_create_wq(context, wq_init_attr);
+}
+
+static int
+mlx4_glue_destroy_wq(struct ibv_wq *wq)
+{
+	return ibv_destroy_wq(wq);
+}
+static int
+mlx4_glue_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr)
+{
+	return ibv_modify_wq(wq, wq_attr);
+}
+
+static int
+mlx4_glue_dv_init_obj(struct mlx4dv_obj *obj, uint64_t obj_type)
+{
+	return mlx4dv_init_obj(obj, obj_type);
+}
+
+static int
+mlx4_glue_dv_set_context_attr(struct ibv_context *context,
+			      enum mlx4dv_set_ctx_attr_type attr_type,
+			      void *attr)
+{
+	return mlx4dv_set_context_attr(context, attr_type, attr);
+}
+
+const struct mlx4_glue *mlx4_glue = &(const struct mlx4_glue){
+	.fork_init = mlx4_glue_fork_init,
+	.get_async_event = mlx4_glue_get_async_event,
+	.ack_async_event = mlx4_glue_ack_async_event,
+	.alloc_pd = mlx4_glue_alloc_pd,
+	.dealloc_pd = mlx4_glue_dealloc_pd,
+	.get_device_list = mlx4_glue_get_device_list,
+	.free_device_list = mlx4_glue_free_device_list,
+	.open_device = mlx4_glue_open_device,
+	.close_device = mlx4_glue_close_device,
+	.get_device_name = mlx4_glue_get_device_name,
+	.query_device = mlx4_glue_query_device,
+	.query_device_ex = mlx4_glue_query_device_ex,
+	.query_port = mlx4_glue_query_port,
+	.port_state_str = mlx4_glue_port_state_str,
+	.create_comp_channel = mlx4_glue_create_comp_channel,
+	.destroy_comp_channel = mlx4_glue_destroy_comp_channel,
+	.create_cq = mlx4_glue_create_cq,
+	.destroy_cq = mlx4_glue_destroy_cq,
+	.get_cq_event = mlx4_glue_get_cq_event,
+	.ack_cq_events = mlx4_glue_ack_cq_events,
+	.create_flow = mlx4_glue_create_flow,
+	.destroy_flow = mlx4_glue_destroy_flow,
+	.create_qp = mlx4_glue_create_qp,
+	.create_qp_ex = mlx4_glue_create_qp_ex,
+	.destroy_qp = mlx4_glue_destroy_qp,
+	.modify_qp = mlx4_glue_modify_qp,
+	.reg_mr = mlx4_glue_reg_mr,
+	.dereg_mr = mlx4_glue_dereg_mr,
+	.create_rwq_ind_table = mlx4_glue_create_rwq_ind_table,
+	.destroy_rwq_ind_table = mlx4_glue_destroy_rwq_ind_table,
+	.create_wq = mlx4_glue_create_wq,
+	.destroy_wq = mlx4_glue_destroy_wq,
+	.modify_wq = mlx4_glue_modify_wq,
+	.dv_init_obj = mlx4_glue_dv_init_obj,
+	.dv_set_context_attr = mlx4_glue_dv_set_context_attr,
+};
diff --git a/drivers/net/mlx4/mlx4_glue.h b/drivers/net/mlx4/mlx4_glue.h
new file mode 100644
index 000000000..0623511f2
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_glue.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox
+ */
+
+#ifndef MLX4_GLUE_H_
+#define MLX4_GLUE_H_
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx4dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+struct mlx4_glue {
+	int (*fork_init)(void);
+	int (*get_async_event)(struct ibv_context *context,
+			       struct ibv_async_event *event);
+	void (*ack_async_event)(struct ibv_async_event *event);
+	struct ibv_pd *(*alloc_pd)(struct ibv_context *context);
+	int (*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_device **(*get_device_list)(int *num_devices);
+	void (*free_device_list)(struct ibv_device **list);
+	struct ibv_context *(*open_device)(struct ibv_device *device);
+	int (*close_device)(struct ibv_context *context);
+	const char *(*get_device_name)(struct ibv_device *device);
+	int (*query_device)(struct ibv_context *context,
+			    struct ibv_device_attr *device_attr);
+	int (*query_device_ex)(struct ibv_context *context,
+			       const struct ibv_query_device_ex_input *input,
+			       struct ibv_device_attr_ex *attr);
+	int (*query_port)(struct ibv_context *context, uint8_t port_num,
+			  struct ibv_port_attr *port_attr);
+	const char *(*port_state_str)(enum ibv_port_state port_state);
+	struct ibv_comp_channel *(*create_comp_channel)
+		(struct ibv_context *context);
+	int (*destroy_comp_channel)(struct ibv_comp_channel *channel);
+	struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe,
+				    void *cq_context,
+				    struct ibv_comp_channel *channel,
+				    int comp_vector);
+	int (*destroy_cq)(struct ibv_cq *cq);
+	int (*get_cq_event)(struct ibv_comp_channel *channel,
+			    struct ibv_cq **cq, void **cq_context);
+	void (*ack_cq_events)(struct ibv_cq *cq, unsigned int nevents);
+	struct ibv_flow *(*create_flow)(struct ibv_qp *qp,
+					struct ibv_flow_attr *flow);
+	int (*destroy_flow)(struct ibv_flow *flow_id);
+	struct ibv_qp *(*create_qp)(struct ibv_pd *pd,
+				    struct ibv_qp_init_attr *qp_init_attr);
+	struct ibv_qp *(*create_qp_ex)
+		(struct ibv_context *context,
+		 struct ibv_qp_init_attr_ex *qp_init_attr_ex);
+	int (*destroy_qp)(struct ibv_qp *qp);
+	int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+			 int attr_mask);
+	struct ibv_mr *(*reg_mr)(struct ibv_pd *pd, void *addr,
+				 size_t length, int access);
+	int (*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_rwq_ind_table *(*create_rwq_ind_table)
+		(struct ibv_context *context,
+		 struct ibv_rwq_ind_table_init_attr *init_attr);
+	int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table);
+	struct ibv_wq *(*create_wq)(struct ibv_context *context,
+				    struct ibv_wq_init_attr *wq_init_attr);
+	int (*destroy_wq)(struct ibv_wq *wq);
+	int (*modify_wq)(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr);
+	int (*dv_init_obj)(struct mlx4dv_obj *obj, uint64_t obj_type);
+	int (*dv_set_context_attr)(struct ibv_context *context,
+				   enum mlx4dv_set_ctx_attr_type attr_type,
+				   void *attr);
+};
+
+const struct mlx4_glue *mlx4_glue;
+
+#endif /* MLX4_GLUE_H_ */
diff --git a/drivers/net/mlx4/mlx4_intr.c b/drivers/net/mlx4/mlx4_intr.c
index 2ff72188a..d5ab170f9 100644
--- a/drivers/net/mlx4/mlx4_intr.c
+++ b/drivers/net/mlx4/mlx4_intr.c
@@ -57,6 +57,7 @@
 #include <rte_interrupts.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -216,7 +217,7 @@ mlx4_interrupt_handler(struct priv *priv)
 	unsigned int i;
 
 	/* Read all message and acknowledge them. */
-	while (!ibv_get_async_event(priv->ctx, &event)) {
+	while (!mlx4_glue->get_async_event(priv->ctx, &event)) {
 		switch (event.event_type) {
 		case IBV_EVENT_PORT_ACTIVE:
 		case IBV_EVENT_PORT_ERR:
@@ -231,7 +232,7 @@ mlx4_interrupt_handler(struct priv *priv)
 			DEBUG("event type %d on physical port %d not handled",
 			      event.event_type, event.element.port_num);
 		}
-		ibv_ack_async_event(&event);
+		mlx4_glue->ack_async_event(&event);
 	}
 	for (i = 0; i != RTE_DIM(caught); ++i)
 		if (caught[i])
@@ -354,7 +355,8 @@ mlx4_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
 	if (!rxq || !rxq->channel) {
 		ret = EINVAL;
 	} else {
-		ret = ibv_get_cq_event(rxq->cq->channel, &ev_cq, &ev_ctx);
+		ret = mlx4_glue->get_cq_event(rxq->cq->channel, &ev_cq,
+					      &ev_ctx);
 		if (ret || ev_cq != rxq->cq)
 			ret = EINVAL;
 	}
@@ -364,7 +366,7 @@ mlx4_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
 		     idx);
 	} else {
 		rxq->mcq.arm_sn++;
-		ibv_ack_cq_events(rxq->cq, 1);
+		mlx4_glue->ack_cq_events(rxq->cq, 1);
 	}
 	return -ret;
 }
diff --git a/drivers/net/mlx4/mlx4_mr.c b/drivers/net/mlx4/mlx4_mr.c
index 2a3e2695b..493c00867 100644
--- a/drivers/net/mlx4/mlx4_mr.c
+++ b/drivers/net/mlx4/mlx4_mr.c
@@ -60,6 +60,7 @@
 #include <rte_mempool.h>
 #include <rte_spinlock.h>
 
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -200,8 +201,8 @@ mlx4_mr_get(struct priv *priv, struct rte_mempool *mp)
 		.end = end,
 		.refcnt = 1,
 		.priv = priv,
-		.mr = ibv_reg_mr(priv->pd, (void *)start, end - start,
-				 IBV_ACCESS_LOCAL_WRITE),
+		.mr = mlx4_glue->reg_mr(priv->pd, (void *)start, end - start,
+					IBV_ACCESS_LOCAL_WRITE),
 		.mp = mp,
 	};
 	if (mr->mr) {
@@ -240,7 +241,7 @@ mlx4_mr_put(struct mlx4_mr *mr)
 	if (--mr->refcnt)
 		goto release;
 	LIST_REMOVE(mr, next);
-	claim_zero(ibv_dereg_mr(mr->mr));
+	claim_zero(mlx4_glue->dereg_mr(mr->mr));
 	rte_free(mr);
 release:
 	rte_spinlock_unlock(&priv->mr_lock);
diff --git a/drivers/net/mlx4/mlx4_rxq.c b/drivers/net/mlx4/mlx4_rxq.c
index 163598765..bf60d2fc8 100644
--- a/drivers/net/mlx4/mlx4_rxq.c
+++ b/drivers/net/mlx4/mlx4_rxq.c
@@ -62,6 +62,7 @@
 #include <rte_mempool.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -231,7 +232,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		}
 		ind_tbl[i] = rxq->wq;
 	}
-	rss->ind = ibv_create_rwq_ind_table
+	rss->ind = mlx4_glue->create_rwq_ind_table
 		(priv->ctx,
 		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = rte_log2_u32(RTE_DIM(ind_tbl)),
@@ -243,7 +244,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "RSS indirection table creation failure";
 		goto error;
 	}
-	rss->qp = ibv_create_qp_ex
+	rss->qp = mlx4_glue->create_qp_ex
 		(priv->ctx,
 		 &(struct ibv_qp_init_attr_ex){
 			.comp_mask = (IBV_QP_INIT_ATTR_PD |
@@ -264,7 +265,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "RSS hash QP creation failure";
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(rss->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_INIT,
@@ -275,7 +276,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "failed to switch RSS hash QP to INIT state";
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(rss->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTR,
@@ -288,11 +289,11 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 	return 0;
 error:
 	if (rss->qp) {
-		claim_zero(ibv_destroy_qp(rss->qp));
+		claim_zero(mlx4_glue->destroy_qp(rss->qp));
 		rss->qp = NULL;
 	}
 	if (rss->ind) {
-		claim_zero(ibv_destroy_rwq_ind_table(rss->ind));
+		claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind));
 		rss->ind = NULL;
 	}
 	while (i--)
@@ -325,9 +326,9 @@ mlx4_rss_detach(struct mlx4_rss *rss)
 	assert(rss->ind);
 	if (--rss->usecnt)
 		return;
-	claim_zero(ibv_destroy_qp(rss->qp));
+	claim_zero(mlx4_glue->destroy_qp(rss->qp));
 	rss->qp = NULL;
-	claim_zero(ibv_destroy_rwq_ind_table(rss->ind));
+	claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind));
 	rss->ind = NULL;
 	for (i = 0; i != rss->queues; ++i)
 		mlx4_rxq_detach(priv->dev->data->rx_queues[rss->queue_id[i]]);
@@ -364,9 +365,10 @@ mlx4_rss_init(struct priv *priv)
 	int ret;
 
 	/* Prepare range for RSS contexts before creating the first WQ. */
-	ret = mlx4dv_set_context_attr(priv->ctx,
-				      MLX4DV_SET_CTX_ATTR_LOG_WQS_RANGE_SZ,
-				      &log2_range);
+	ret = mlx4_glue->dv_set_context_attr
+		(priv->ctx,
+		 MLX4DV_SET_CTX_ATTR_LOG_WQS_RANGE_SZ,
+		 &log2_range);
 	if (ret) {
 		ERROR("cannot set up range size for RSS context to %u"
 		      " (for %u Rx queues), error: %s",
@@ -402,13 +404,13 @@ mlx4_rss_init(struct priv *priv)
 		 * sequentially and are guaranteed to never be reused in the
 		 * same context by the underlying implementation.
 		 */
-		cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+		cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 		if (!cq) {
 			ret = ENOMEM;
 			msg = "placeholder CQ creation failure";
 			goto error;
 		}
-		wq = ibv_create_wq
+		wq = mlx4_glue->create_wq
 			(priv->ctx,
 			 &(struct ibv_wq_init_attr){
 				.wq_type = IBV_WQT_RQ,
@@ -419,11 +421,11 @@ mlx4_rss_init(struct priv *priv)
 			 });
 		if (wq) {
 			wq_num = wq->wq_num;
-			claim_zero(ibv_destroy_wq(wq));
+			claim_zero(mlx4_glue->destroy_wq(wq));
 		} else {
 			wq_num = 0; /* Shut up GCC 4.8 warnings. */
 		}
-		claim_zero(ibv_destroy_cq(cq));
+		claim_zero(mlx4_glue->destroy_cq(cq));
 		if (!wq) {
 			ret = ENOMEM;
 			msg = "placeholder WQ creation failure";
@@ -522,13 +524,14 @@ mlx4_rxq_attach(struct rxq *rxq)
 	int ret;
 
 	assert(rte_is_power_of_2(elts_n));
-	cq = ibv_create_cq(priv->ctx, elts_n / sges_n, NULL, rxq->channel, 0);
+	cq = mlx4_glue->create_cq(priv->ctx, elts_n / sges_n, NULL,
+				  rxq->channel, 0);
 	if (!cq) {
 		ret = ENOMEM;
 		msg = "CQ creation failure";
 		goto error;
 	}
-	wq = ibv_create_wq
+	wq = mlx4_glue->create_wq
 		(priv->ctx,
 		 &(struct ibv_wq_init_attr){
 			.wq_type = IBV_WQT_RQ,
@@ -542,7 +545,7 @@ mlx4_rxq_attach(struct rxq *rxq)
 		msg = "WQ creation failure";
 		goto error;
 	}
-	ret = ibv_modify_wq
+	ret = mlx4_glue->modify_wq
 		(wq,
 		 &(struct ibv_wq_attr){
 			.attr_mask = IBV_WQ_ATTR_STATE,
@@ -557,7 +560,7 @@ mlx4_rxq_attach(struct rxq *rxq)
 	mlxdv.cq.out = &dv_cq;
 	mlxdv.rwq.in = wq;
 	mlxdv.rwq.out = &dv_rwq;
-	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_RWQ | MLX4DV_OBJ_CQ);
+	ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_RWQ | MLX4DV_OBJ_CQ);
 	if (ret) {
 		msg = "failed to obtain device information from WQ/CQ objects";
 		goto error;
@@ -619,9 +622,9 @@ mlx4_rxq_attach(struct rxq *rxq)
 	return 0;
 error:
 	if (wq)
-		claim_zero(ibv_destroy_wq(wq));
+		claim_zero(mlx4_glue->destroy_wq(wq));
 	if (cq)
-		claim_zero(ibv_destroy_cq(cq));
+		claim_zero(mlx4_glue->destroy_cq(cq));
 	rte_errno = ret;
 	ERROR("error while attaching Rx queue %p: %s: %s",
 	      (void *)rxq, msg, strerror(ret));
@@ -649,9 +652,9 @@ mlx4_rxq_detach(struct rxq *rxq)
 	memset(&rxq->mcq, 0, sizeof(rxq->mcq));
 	rxq->rq_db = NULL;
 	rxq->wqes = NULL;
-	claim_zero(ibv_destroy_wq(rxq->wq));
+	claim_zero(mlx4_glue->destroy_wq(rxq->wq));
 	rxq->wq = NULL;
-	claim_zero(ibv_destroy_cq(rxq->cq));
+	claim_zero(mlx4_glue->destroy_cq(rxq->cq));
 	rxq->cq = NULL;
 	DEBUG("%p: freeing Rx queue elements", (void *)rxq);
 	for (i = 0; (i != RTE_DIM(*elts)); ++i) {
@@ -879,7 +882,7 @@ mlx4_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		goto error;
 	}
 	if (dev->data->dev_conf.intr_conf.rxq) {
-		rxq->channel = ibv_create_comp_channel(priv->ctx);
+		rxq->channel = mlx4_glue->create_comp_channel(priv->ctx);
 		if (rxq->channel == NULL) {
 			rte_errno = ENOMEM;
 			ERROR("%p: Rx interrupt completion channel creation"
@@ -934,7 +937,7 @@ mlx4_rx_queue_release(void *dpdk_rxq)
 	assert(!rxq->wqes);
 	assert(!rxq->rq_db);
 	if (rxq->channel)
-		claim_zero(ibv_destroy_comp_channel(rxq->channel));
+		claim_zero(mlx4_glue->destroy_comp_channel(rxq->channel));
 	if (rxq->mr)
 		mlx4_mr_put(rxq->mr);
 	rte_free(rxq);
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 2bd4b9cb6..5e4d701cd 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -60,6 +60,7 @@
 #include <rte_mempool.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_prm.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -350,7 +351,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		.lb = !!priv->vf,
 		.bounce_buf = bounce_buf,
 	};
-	txq->cq = ibv_create_cq(priv->ctx, desc, NULL, NULL, 0);
+	txq->cq = mlx4_glue->create_cq(priv->ctx, desc, NULL, NULL, 0);
 	if (!txq->cq) {
 		rte_errno = ENOMEM;
 		ERROR("%p: CQ creation failure: %s",
@@ -370,7 +371,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		/* No completion events must occur by default. */
 		.sq_sig_all = 0,
 	};
-	txq->qp = ibv_create_qp(priv->pd, &qp_init_attr);
+	txq->qp = mlx4_glue->create_qp(priv->pd, &qp_init_attr);
 	if (!txq->qp) {
 		rte_errno = errno ? errno : EINVAL;
 		ERROR("%p: QP creation failure: %s",
@@ -378,7 +379,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		goto error;
 	}
 	txq->max_inline = qp_init_attr.cap.max_inline_data;
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_INIT,
@@ -391,7 +392,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTR,
@@ -403,7 +404,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTS,
@@ -420,7 +421,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 	mlxdv.cq.out = &dv_cq;
 	mlxdv.qp.in = txq->qp;
 	mlxdv.qp.out = &dv_qp;
-	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
+	ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
 	if (ret) {
 		rte_errno = EINVAL;
 		ERROR("%p: failed to obtain information needed for"
@@ -470,9 +471,9 @@ mlx4_tx_queue_release(void *dpdk_txq)
 		}
 	mlx4_txq_free_elts(txq);
 	if (txq->qp)
-		claim_zero(ibv_destroy_qp(txq->qp));
+		claim_zero(mlx4_glue->destroy_qp(txq->qp));
 	if (txq->cq)
-		claim_zero(ibv_destroy_cq(txq->cq));
+		claim_zero(mlx4_glue->destroy_cq(txq->cq));
 	for (i = 0; i != RTE_DIM(txq->mp2mr); ++i) {
 		if (!txq->mp2mr[i].mp)
 			break;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v2 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-26 14:18 ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  2018-01-26 14:18   ` [PATCH v2 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
@ 2018-01-26 14:19   ` Adrien Mazarguil
  2018-01-27 15:03     ` Marcelo Ricardo Leitner
  2018-01-26 14:19   ` [PATCH v2 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-26 14:19 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

When mlx4 is not compiled directly as an independent shared object (e.g.
CONFIG_RTE_BUILD_SHARED_LIB not enabled for performance reasons), DPDK
applications inherit its dependencies on libibverbs and libmlx4 through
rte.app.mk.

This is an issue both when DPDK is delivered as a binary package (Linux
distributions) and for end users because rdma-core then propagates as a
mandatory dependency for everything.

Application writers relying on binary DPDK packages are not necessarily
aware of this fact and may end up delivering packages with broken
dependencies.

This patch therefore introduces an intermediate internal plug-in
hard-linked with rdma-core (to preserve symbol versioning) loaded by the
PMD through dlopen(), so that a missing rdma-core does not cause unresolved
symbols, allowing applications to start normally.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 config/common_base        |  1 +
 doc/guides/nics/mlx4.rst  | 13 +++++++
 drivers/net/mlx4/Makefile | 41 ++++++++++++++++++++++
 drivers/net/mlx4/mlx4.c   | 80 ++++++++++++++++++++++++++++++++++++++++++
 mk/rte.app.mk             |  4 +++
 5 files changed, 139 insertions(+)

diff --git a/config/common_base b/config/common_base
index 170a38939..f29f9e3a0 100644
--- a/config/common_base
+++ b/config/common_base
@@ -298,6 +298,7 @@ CONFIG_RTE_LIBRTE_AVF_16BYTE_RX_DESC=n
 #
 CONFIG_RTE_LIBRTE_MLX4_PMD=n
 CONFIG_RTE_LIBRTE_MLX4_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS=y
 CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8
 
 #
diff --git a/doc/guides/nics/mlx4.rst b/doc/guides/nics/mlx4.rst
index cab45dfe8..1bff400fb 100644
--- a/doc/guides/nics/mlx4.rst
+++ b/doc/guides/nics/mlx4.rst
@@ -86,6 +86,19 @@ These options can be modified in the ``.config`` file.
 
   Toggle compilation of librte_pmd_mlx4 itself.
 
+- ``CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS`` (default **y**)
+
+  Build PMD with additional code to make it loadable without hard
+  dependencies on **libibverbs** nor **libmlx4**, which may not be installed
+  on the target system.
+
+  In this mode, their presence is still required for it to run properly,
+  however their absence won't prevent a DPDK application from starting (with
+  ``CONFIG_RTE_BUILD_SHARED_LIB`` disabled) and they won't show up as
+  missing with ``ldd(1)``.
+
+  This option has no performance impact.
+
 - ``CONFIG_RTE_LIBRTE_MLX4_DEBUG`` (default **n**)
 
   Toggle debugging code and stricter compilation flags. Enabling this option
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1d33c38ed..4ff49a087 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -38,7 +38,11 @@ LIB = librte_pmd_mlx4.a
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_flow.c
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue_lib.c
+else
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue.c
+endif
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_intr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxq.c
@@ -55,7 +59,12 @@ CFLAGS += -D_BSD_SOURCE
 CFLAGS += -D_DEFAULT_SOURCE
 CFLAGS += -D_XOPEN_SOURCE=600
 CFLAGS += $(WERROR_FLAGS)
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+CFLAGS_mlx4_glue.o += -fPIC
+LDLIBS += -ldl
+else
 LDLIBS += -libverbs -lmlx4
+endif
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
@@ -109,7 +118,39 @@ mlx4_autoconf.h: mlx4_autoconf.h.new
 
 $(SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD):.c=.o): mlx4_autoconf.h
 
+# Generate dependency plug-in for rdma-core when the PMD must not be linked
+# directly, so that applications do not inherit this dependency.
+
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+
+mlx4_glue_lib.c: mlx4_glue_lib.so
+	$Q printf '#include <stddef.h>\n' > $@
+	$Q printf '#include <stdint.h>\n\n' >> $@
+	$Q printf 'const uint8_t mlx4_glue_lib[][16] = {\n' >> $@
+	$Q od -vt x1 $< | \
+	sed -ne '/^[[:xdigit:]]\{1,\}/{' \
+		-e 's///;' \
+		-e '/^$$/d; ' \
+		-e 's/[[:space:]]*$$//;' \
+		-e 's/[[:space:]]\{1,\}/\\x/g;' \
+		-e 's/^/	"/;' \
+		-e 's/$$/",/;' \
+		-e 'p;' \
+		-e '}' >> $@
+	$Q printf '};\n\n' >> $@
+	$Q printf 'const size_t mlx4_glue_lib_size = %u;\n' \
+		$$(wc -c < $<) >> $@
+
+mlx4_glue_lib.so: mlx4_glue.o
+	$Q $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) \
+		-s -shared -o $@ $< -libverbs -lmlx4
+
+mlx4_glue.o: mlx4_autoconf.h
+
+endif
+
 clean_mlx4: FORCE
 	$Q rm -f -- mlx4_autoconf.h mlx4_autoconf.h.new
+	$Q rm -f -- mlx4_glue.o mlx4_glue_lib.*
 
 clean: clean_mlx4
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 0fd9a999c..979e29291 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -37,6 +37,7 @@
  */
 
 #include <assert.h>
+#include <dlfcn.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <stddef.h>
@@ -44,6 +45,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 /* Verbs headers do not support -pedantic. */
 #ifdef PEDANTIC
@@ -55,6 +57,7 @@
 #endif
 
 #include <rte_common.h>
+#include <rte_config.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
 #include <rte_ethdev_driver.h>
@@ -724,6 +727,78 @@ static struct rte_pci_driver mlx4_driver = {
 		     RTE_PCI_DRV_INTR_RMV,
 };
 
+#ifdef RTE_LIBRTE_MLX4_DLOPEN_DEPS
+
+extern const uint8_t mlx4_glue_lib[][16];
+extern const size_t mlx4_glue_lib_size;
+
+/**
+ * Initialization routine for run-time dependency on rdma-core.
+ */
+static int
+mlx4_glue_init(void)
+{
+	char file[] = "/tmp/" MLX4_DRIVER_NAME "_XXXXXX";
+	int fd = mkstemp(file);
+	size_t off = 0;
+	void *handle = NULL;
+	void **sym;
+	const char *dlmsg;
+
+	if (fd == -1) {
+		rte_errno = errno;
+		goto glue_error;
+	}
+	while (off != mlx4_glue_lib_size) {
+		ssize_t ret;
+
+		ret = write(fd, (const uint8_t *)mlx4_glue_lib + off,
+			    mlx4_glue_lib_size - off);
+		if (ret == -1) {
+			if (errno != EINTR) {
+				rte_errno = errno;
+				goto glue_error;
+			}
+			ret = 0;
+		}
+		off += ret;
+	}
+	close(fd);
+	fd = -1;
+	handle = dlopen(file, RTLD_LAZY);
+	unlink(file);
+	if (!handle) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot load glue library: %s", dlmsg);
+		goto glue_error;
+	}
+	sym = dlsym(handle, "mlx4_glue");
+	if (!sym || !*sym) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot resolve glue symbol: %s", dlmsg);
+		goto glue_error;
+	}
+	mlx4_glue = *sym;
+	return 0;
+glue_error:
+	if (handle)
+		dlclose(handle);
+	if (fd != -1) {
+		close(fd);
+		unlink(file);
+	}
+	ERROR("cannot initialize PMD due to missing run-time"
+	      " dependency on rdma-core libraries (libibverbs,"
+	      " libmlx4)");
+	return -rte_errno;
+}
+
+#endif
+
 /**
  * Driver initialization routine.
  */
@@ -744,6 +819,11 @@ rte_mlx4_pmd_init(void)
 	 * using this PMD, which is not supported in forked processes.
 	 */
 	setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
+#ifdef RTE_LIBRTE_MLX4_DLOPEN_DEPS
+	if (mlx4_glue_init())
+		return;
+	assert(mlx4_glue);
+#endif
 	mlx4_glue->fork_init();
 	rte_pci_register(&mlx4_driver);
 }
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 0169f3f5b..fdbe36630 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -143,7 +143,11 @@ ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KNI)        += -lrte_pmd_kni
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -ldl
+else
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs -lmlx4
+endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs -lmlx5
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v2 3/4] net/mlx5: move rdma-core calls to separate file
  2018-01-26 14:18 ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  2018-01-26 14:18   ` [PATCH v2 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
  2018-01-26 14:19   ` [PATCH v2 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-26 14:19   ` Adrien Mazarguil
  2018-01-26 14:19   ` [PATCH v2 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-26 14:19 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

From: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>

This lays the groundwork for externalizing rdma-core as an optional
run-time dependency instead of a mandatory one.

No functional change.

Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 drivers/net/mlx5/Makefile      |   1 +
 drivers/net/mlx5/mlx5.c        |  44 ++---
 drivers/net/mlx5/mlx5_ethdev.c |   7 +-
 drivers/net/mlx5/mlx5_flow.c   |  92 +++++------
 drivers/net/mlx5/mlx5_glue.c   | 321 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h   |  99 +++++++++++
 drivers/net/mlx5/mlx5_mr.c     |   7 +-
 drivers/net/mlx5/mlx5_rxq.c    |  54 +++---
 drivers/net/mlx5/mlx5_txq.c    |  22 +--
 drivers/net/mlx5/mlx5_vlan.c   |  13 +-
 10 files changed, 548 insertions(+), 112 deletions(-)

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index a3984eb9f..bdec30692 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -53,6 +53,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
 
 # Basic CFLAGS.
 CFLAGS += -O3
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 5a959f7c5..b911d0ad4 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -65,6 +65,7 @@
 #include "mlx5_rxtx.h"
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
+#include "mlx5_glue.h"
 
 /* Device parameter to enable RX completion queue compression. */
 #define MLX5_RXQ_CQE_COMP_EN "rxq_cqe_comp_en"
@@ -218,8 +219,8 @@ mlx5_dev_close(struct rte_eth_dev *dev)
 	}
 	if (priv->pd != NULL) {
 		assert(priv->ctx != NULL);
-		claim_zero(ibv_dealloc_pd(priv->pd));
-		claim_zero(ibv_close_device(priv->ctx));
+		claim_zero(mlx5_glue->dealloc_pd(priv->pd));
+		claim_zero(mlx5_glue->close_device(priv->ctx));
 	} else
 		assert(priv->ctx == NULL);
 	if (priv->rss_conf.rss_key != NULL)
@@ -625,7 +626,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 	/* Save PCI address. */
 	mlx5_dev[idx].pci_addr = pci_dev->addr;
-	list = ibv_get_device_list(&i);
+	list = mlx5_glue->get_device_list(&i);
 	if (list == NULL) {
 		assert(errno);
 		if (errno == ENOSYS)
@@ -675,12 +676,12 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		     " (SR-IOV: %s)",
 		     list[i]->name,
 		     sriov ? "true" : "false");
-		attr_ctx = ibv_open_device(list[i]);
+		attr_ctx = mlx5_glue->open_device(list[i]);
 		err = errno;
 		break;
 	}
 	if (attr_ctx == NULL) {
-		ibv_free_device_list(list);
+		mlx5_glue->free_device_list(list);
 		switch (err) {
 		case 0:
 			ERROR("cannot access device, is mlx5_ib loaded?");
@@ -699,7 +700,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	 * Multi-packet send is supported by ConnectX-4 Lx PF as well
 	 * as all ConnectX-5 devices.
 	 */
-	mlx5dv_query_device(attr_ctx, &attrs_out);
+	mlx5_glue->dv_query_device(attr_ctx, &attrs_out);
 	if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_MPW_ALLOWED) {
 		if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_ENHANCED_MPW) {
 			DEBUG("Enhanced MPW is supported");
@@ -717,7 +718,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		cqe_comp = 0;
 	else
 		cqe_comp = 1;
-	if (ibv_query_device_ex(attr_ctx, NULL, &device_attr))
+	if (mlx5_glue->query_device_ex(attr_ctx, NULL, &device_attr))
 		goto error;
 	INFO("%u port(s) detected", device_attr.orig_attr.phys_port_cnt);
 
@@ -794,15 +795,15 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 		DEBUG("using port %u (%08" PRIx32 ")", port, test);
 
-		ctx = ibv_open_device(ibv_dev);
+		ctx = mlx5_glue->open_device(ibv_dev);
 		if (ctx == NULL) {
 			err = ENODEV;
 			goto port_error;
 		}
 
-		ibv_query_device_ex(ctx, NULL, &device_attr);
+		mlx5_glue->query_device_ex(ctx, NULL, &device_attr);
 		/* Check port status. */
-		err = ibv_query_port(ctx, port, &port_attr);
+		err = mlx5_glue->query_port(ctx, port, &port_attr);
 		if (err) {
 			ERROR("port query failed: %s", strerror(err));
 			goto port_error;
@@ -817,11 +818,11 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 		if (port_attr.state != IBV_PORT_ACTIVE)
 			DEBUG("port %d is not active: \"%s\" (%d)",
-			      port, ibv_port_state_str(port_attr.state),
+			      port, mlx5_glue->port_state_str(port_attr.state),
 			      port_attr.state);
 
 		/* Allocate protection domain. */
-		pd = ibv_alloc_pd(ctx);
+		pd = mlx5_glue->alloc_pd(ctx);
 		if (pd == NULL) {
 			ERROR("PD allocation failure");
 			err = ENOMEM;
@@ -853,7 +854,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			      strerror(err));
 			goto port_error;
 		}
-		if (ibv_query_device_ex(ctx, NULL, &device_attr_ex)) {
+		if (mlx5_glue->query_device_ex(ctx, NULL, &device_attr_ex)) {
 			ERROR("ibv_query_device_ex() failed");
 			goto port_error;
 		}
@@ -873,7 +874,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
 		config.flow_counter_en = !!(device_attr.max_counter_sets);
-		ibv_describe_counter_set(ctx, 0, &cs_desc);
+		mlx5_glue->describe_counter_set(ctx, 0, &cs_desc);
 		DEBUG("counter type = %d, num of cs = %ld, attributes = %d",
 		      cs_desc.counter_type, cs_desc.num_of_cs,
 		      cs_desc.attributes);
@@ -984,8 +985,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			.free = &mlx5_free_verbs_buf,
 			.data = priv,
 		};
-		mlx5dv_set_context_attr(ctx, MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
-					(void *)((uintptr_t)&alctr));
+		mlx5_glue->dv_set_context_attr(ctx,
+					       MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
+					       (void *)((uintptr_t)&alctr));
 
 		/* Bring Ethernet device up. */
 		DEBUG("forcing Ethernet interface up");
@@ -998,9 +1000,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		if (priv)
 			rte_free(priv);
 		if (pd)
-			claim_zero(ibv_dealloc_pd(pd));
+			claim_zero(mlx5_glue->dealloc_pd(pd));
 		if (ctx)
-			claim_zero(ibv_close_device(ctx));
+			claim_zero(mlx5_glue->close_device(ctx));
 		break;
 	}
 
@@ -1019,9 +1021,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 error:
 	if (attr_ctx)
-		claim_zero(ibv_close_device(attr_ctx));
+		claim_zero(mlx5_glue->close_device(attr_ctx));
 	if (list)
-		ibv_free_device_list(list);
+		mlx5_glue->free_device_list(list);
 	assert(err >= 0);
 	return -err;
 }
@@ -1092,7 +1094,7 @@ rte_mlx5_pmd_init(void)
 	/* Match the size of Rx completion entry to the size of a cacheline. */
 	if (RTE_CACHE_LINE_SIZE == 128)
 		setenv("MLX5_CQE_SIZE", "128", 0);
-	ibv_fork_init();
+	mlx5_glue->fork_init();
 	rte_pci_register(&mlx5_driver);
 }
 
diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c
index 83657f509..cbc735a8b 100644
--- a/drivers/net/mlx5/mlx5_ethdev.c
+++ b/drivers/net/mlx5/mlx5_ethdev.c
@@ -64,6 +64,7 @@
 #include <rte_malloc.h>
 
 #include "mlx5.h"
+#include "mlx5_glue.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_utils.h"
 
@@ -1261,7 +1262,7 @@ priv_dev_status_handler(struct priv *priv)
 
 	/* Read all message and acknowledge them. */
 	for (;;) {
-		if (ibv_get_async_event(priv->ctx, &event))
+		if (mlx5_glue->get_async_event(priv->ctx, &event))
 			break;
 		if ((event.event_type == IBV_EVENT_PORT_ACTIVE ||
 			event.event_type == IBV_EVENT_PORT_ERR) &&
@@ -1273,7 +1274,7 @@ priv_dev_status_handler(struct priv *priv)
 		else
 			DEBUG("event type %d on port %d not handled",
 			      event.event_type, event.element.port_num);
-		ibv_ack_async_event(&event);
+		mlx5_glue->ack_async_event(&event);
 	}
 	if (ret & (1 << RTE_ETH_EVENT_INTR_LSC))
 		if (priv_link_status_update(priv))
@@ -1559,7 +1560,7 @@ mlx5_is_removed(struct rte_eth_dev *dev)
 	struct ibv_device_attr device_attr;
 	struct priv *priv = dev->data->dev_private;
 
-	if (ibv_query_device(priv->ctx, &device_attr) == EIO)
+	if (mlx5_glue->query_device(priv->ctx, &device_attr) == EIO)
 		return 1;
 	return 0;
 }
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index bf8eff8a5..800ec9f07 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -53,6 +53,7 @@
 #include "mlx5.h"
 #include "mlx5_defs.h"
 #include "mlx5_prm.h"
+#include "mlx5_glue.h"
 
 /* Define minimal priority for control plane flows. */
 #define MLX5_CTRL_FLOW_PRIORITY 4
@@ -62,22 +63,9 @@
 #define MLX5_IPV6 6
 
 #ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
-struct ibv_counter_set_init_attr {
-	int dummy;
-};
 struct ibv_flow_spec_counter_action {
 	int dummy;
 };
-struct ibv_counter_set {
-	int dummy;
-};
-
-static inline int
-ibv_destroy_counter_set(struct ibv_counter_set *cs)
-{
-	(void)cs;
-	return -ENOTSUP;
-}
 #endif
 
 /* Dev ops structure defined in mlx5.c */
@@ -1649,7 +1637,7 @@ mlx5_flow_create_count(struct priv *priv __rte_unused,
 	};
 
 	init_attr.counter_set_id = 0;
-	parser->cs = ibv_create_counter_set(priv->ctx, &init_attr);
+	parser->cs = mlx5_glue->create_counter_set(priv->ctx, &init_attr);
 	if (!parser->cs)
 		return EINVAL;
 	counter.counter_set_handle = parser->cs->handle;
@@ -1702,8 +1690,8 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 		return 0;
 	parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
 	flow->frxq[HASH_RXQ_ETH].ibv_flow =
-		ibv_create_flow(priv->flow_drop_queue->qp,
-				flow->frxq[HASH_RXQ_ETH].ibv_attr);
+		mlx5_glue->create_flow(priv->flow_drop_queue->qp,
+				       flow->frxq[HASH_RXQ_ETH].ibv_attr);
 	if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
 		rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
 				   NULL, "flow rule creation failure");
@@ -1714,7 +1702,8 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 error:
 	assert(flow);
 	if (flow->frxq[HASH_RXQ_ETH].ibv_flow) {
-		claim_zero(ibv_destroy_flow(flow->frxq[HASH_RXQ_ETH].ibv_flow));
+		claim_zero(mlx5_glue->destroy_flow
+			   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 		flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
 	}
 	if (flow->frxq[HASH_RXQ_ETH].ibv_attr) {
@@ -1722,7 +1711,7 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 		flow->frxq[HASH_RXQ_ETH].ibv_attr = NULL;
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 		parser->cs = NULL;
 	}
@@ -1826,8 +1815,8 @@ priv_flow_create_action_queue(struct priv *priv,
 		if (!flow->frxq[i].hrxq)
 			continue;
 		flow->frxq[i].ibv_flow =
-			ibv_create_flow(flow->frxq[i].hrxq->qp,
-					flow->frxq[i].ibv_attr);
+			mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
+					       flow->frxq[i].ibv_attr);
 		if (!flow->frxq[i].ibv_flow) {
 			rte_flow_error_set(error, ENOMEM,
 					   RTE_FLOW_ERROR_TYPE_HANDLE,
@@ -1853,7 +1842,7 @@ priv_flow_create_action_queue(struct priv *priv,
 		if (flow->frxq[i].ibv_flow) {
 			struct ibv_flow *ibv_flow = flow->frxq[i].ibv_flow;
 
-			claim_zero(ibv_destroy_flow(ibv_flow));
+			claim_zero(mlx5_glue->destroy_flow(ibv_flow));
 		}
 		if (flow->frxq[i].hrxq)
 			mlx5_priv_hrxq_release(priv, flow->frxq[i].hrxq);
@@ -1861,7 +1850,7 @@ priv_flow_create_action_queue(struct priv *priv,
 			rte_free(flow->frxq[i].ibv_attr);
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 		parser->cs = NULL;
 	}
@@ -2039,7 +2028,7 @@ priv_flow_destroy(struct priv *priv,
 free:
 	if (flow->drop) {
 		if (flow->frxq[HASH_RXQ_ETH].ibv_flow)
-			claim_zero(ibv_destroy_flow
+			claim_zero(mlx5_glue->destroy_flow
 				   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 		rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
 	} else {
@@ -2047,7 +2036,8 @@ priv_flow_destroy(struct priv *priv,
 			struct mlx5_flow *frxq = &flow->frxq[i];
 
 			if (frxq->ibv_flow)
-				claim_zero(ibv_destroy_flow(frxq->ibv_flow));
+				claim_zero(mlx5_glue->destroy_flow
+					   (frxq->ibv_flow));
 			if (frxq->hrxq)
 				mlx5_priv_hrxq_release(priv, frxq->hrxq);
 			if (frxq->ibv_attr)
@@ -2055,7 +2045,7 @@ priv_flow_destroy(struct priv *priv,
 		}
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 	}
 	TAILQ_REMOVE(list, flow, next);
@@ -2103,35 +2093,38 @@ priv_flow_create_drop_queue(struct priv *priv)
 		WARN("cannot allocate memory for drop queue");
 		goto error;
 	}
-	fdq->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+	fdq->cq = mlx5_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 	if (!fdq->cq) {
 		WARN("cannot allocate CQ for drop queue");
 		goto error;
 	}
-	fdq->wq = ibv_create_wq(priv->ctx,
-			&(struct ibv_wq_init_attr){
+	fdq->wq = mlx5_glue->create_wq
+		(priv->ctx,
+		 &(struct ibv_wq_init_attr){
 			.wq_type = IBV_WQT_RQ,
 			.max_wr = 1,
 			.max_sge = 1,
 			.pd = priv->pd,
 			.cq = fdq->cq,
-			});
+		 });
 	if (!fdq->wq) {
 		WARN("cannot allocate WQ for drop queue");
 		goto error;
 	}
-	fdq->ind_table = ibv_create_rwq_ind_table(priv->ctx,
-			&(struct ibv_rwq_ind_table_init_attr){
+	fdq->ind_table = mlx5_glue->create_rwq_ind_table
+		(priv->ctx,
+		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = 0,
 			.ind_tbl = &fdq->wq,
 			.comp_mask = 0,
-			});
+		 });
 	if (!fdq->ind_table) {
 		WARN("cannot allocate indirection table for drop queue");
 		goto error;
 	}
-	fdq->qp = ibv_create_qp_ex(priv->ctx,
-		&(struct ibv_qp_init_attr_ex){
+	fdq->qp = mlx5_glue->create_qp_ex
+		(priv->ctx,
+		 &(struct ibv_qp_init_attr_ex){
 			.qp_type = IBV_QPT_RAW_PACKET,
 			.comp_mask =
 				IBV_QP_INIT_ATTR_PD |
@@ -2146,7 +2139,7 @@ priv_flow_create_drop_queue(struct priv *priv)
 				},
 			.rwq_ind_tbl = fdq->ind_table,
 			.pd = priv->pd
-		});
+		 });
 	if (!fdq->qp) {
 		WARN("cannot allocate QP for drop queue");
 		goto error;
@@ -2155,13 +2148,13 @@ priv_flow_create_drop_queue(struct priv *priv)
 	return 0;
 error:
 	if (fdq->qp)
-		claim_zero(ibv_destroy_qp(fdq->qp));
+		claim_zero(mlx5_glue->destroy_qp(fdq->qp));
 	if (fdq->ind_table)
-		claim_zero(ibv_destroy_rwq_ind_table(fdq->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
 	if (fdq->wq)
-		claim_zero(ibv_destroy_wq(fdq->wq));
+		claim_zero(mlx5_glue->destroy_wq(fdq->wq));
 	if (fdq->cq)
-		claim_zero(ibv_destroy_cq(fdq->cq));
+		claim_zero(mlx5_glue->destroy_cq(fdq->cq));
 	if (fdq)
 		rte_free(fdq);
 	priv->flow_drop_queue = NULL;
@@ -2182,13 +2175,13 @@ priv_flow_delete_drop_queue(struct priv *priv)
 	if (!fdq)
 		return;
 	if (fdq->qp)
-		claim_zero(ibv_destroy_qp(fdq->qp));
+		claim_zero(mlx5_glue->destroy_qp(fdq->qp));
 	if (fdq->ind_table)
-		claim_zero(ibv_destroy_rwq_ind_table(fdq->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
 	if (fdq->wq)
-		claim_zero(ibv_destroy_wq(fdq->wq));
+		claim_zero(mlx5_glue->destroy_wq(fdq->wq));
 	if (fdq->cq)
-		claim_zero(ibv_destroy_cq(fdq->cq));
+		claim_zero(mlx5_glue->destroy_cq(fdq->cq));
 	rte_free(fdq);
 	priv->flow_drop_queue = NULL;
 }
@@ -2212,7 +2205,7 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
 		if (flow->drop) {
 			if (!flow->frxq[HASH_RXQ_ETH].ibv_flow)
 				continue;
-			claim_zero(ibv_destroy_flow
+			claim_zero(mlx5_glue->destroy_flow
 				   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 			flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
 			/* Next flow. */
@@ -2233,7 +2226,8 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
 		for (i = 0; i != hash_rxq_init_n; ++i) {
 			if (!flow->frxq[i].ibv_flow)
 				continue;
-			claim_zero(ibv_destroy_flow(flow->frxq[i].ibv_flow));
+			claim_zero(mlx5_glue->destroy_flow
+				   (flow->frxq[i].ibv_flow));
 			flow->frxq[i].ibv_flow = NULL;
 			mlx5_priv_hrxq_release(priv, flow->frxq[i].hrxq);
 			flow->frxq[i].hrxq = NULL;
@@ -2263,7 +2257,7 @@ priv_flow_start(struct priv *priv, struct mlx5_flows *list)
 
 		if (flow->drop) {
 			flow->frxq[HASH_RXQ_ETH].ibv_flow =
-				ibv_create_flow
+				mlx5_glue->create_flow
 				(priv->flow_drop_queue->qp,
 				 flow->frxq[HASH_RXQ_ETH].ibv_attr);
 			if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
@@ -2301,8 +2295,8 @@ priv_flow_start(struct priv *priv, struct mlx5_flows *list)
 			}
 flow_create:
 			flow->frxq[i].ibv_flow =
-				ibv_create_flow(flow->frxq[i].hrxq->qp,
-						flow->frxq[i].ibv_attr);
+				mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
+						       flow->frxq[i].ibv_attr);
 			if (!flow->frxq[i].ibv_flow) {
 				DEBUG("Flow %p cannot be applied",
 				      (void *)flow);
@@ -2509,7 +2503,7 @@ priv_flow_query_count(struct ibv_counter_set *cs,
 		.out = counters,
 		.outlen = 2 * sizeof(uint64_t),
 	};
-	int res = ibv_query_counter_set(&query_cs_attr, &query_out);
+	int res = mlx5_glue->query_counter_set(&query_cs_attr, &query_out);
 
 	if (res) {
 		rte_flow_error_set(error, -res,
diff --git a/drivers/net/mlx5/mlx5_glue.c b/drivers/net/mlx5/mlx5_glue.c
new file mode 100644
index 000000000..2ae5a5345
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_glue.c
@@ -0,0 +1,321 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox Technologies, Ltd.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
+
+static int
+mlx5_glue_fork_init(void)
+{
+	return ibv_fork_init();
+}
+
+static struct ibv_pd *
+mlx5_glue_alloc_pd(struct ibv_context *context)
+{
+	return ibv_alloc_pd(context);
+}
+
+static int
+mlx5_glue_dealloc_pd(struct ibv_pd *pd)
+{
+	return ibv_dealloc_pd(pd);
+}
+
+static struct ibv_device **
+mlx5_glue_get_device_list(int *num_devices)
+{
+	return ibv_get_device_list(num_devices);
+}
+
+static void
+mlx5_glue_free_device_list(struct ibv_device **list)
+{
+	ibv_free_device_list(list);
+}
+
+static struct ibv_context *
+mlx5_glue_open_device(struct ibv_device *device)
+{
+	return ibv_open_device(device);
+}
+
+static int
+mlx5_glue_close_device(struct ibv_context *context)
+{
+	return ibv_close_device(context);
+}
+
+static int
+mlx5_glue_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context, device_attr);
+}
+
+static int
+mlx5_glue_query_device_ex(struct ibv_context *context,
+			  const struct ibv_query_device_ex_input *input,
+			  struct ibv_device_attr_ex *attr)
+{
+	return ibv_query_device_ex(context, input, attr);
+}
+
+static int
+mlx5_glue_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context, port_num, port_attr);
+}
+
+static struct ibv_comp_channel *
+mlx5_glue_create_comp_channel(struct ibv_context *context)
+{
+	return ibv_create_comp_channel(context);
+}
+
+static int
+mlx5_glue_destroy_comp_channel(struct ibv_comp_channel *channel)
+{
+	return ibv_destroy_comp_channel(channel);
+}
+
+static struct ibv_cq *
+mlx5_glue_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+		    struct ibv_comp_channel *channel, int comp_vector)
+{
+	return ibv_create_cq(context, cqe, cq_context, channel, comp_vector);
+}
+
+static int
+mlx5_glue_destroy_cq(struct ibv_cq *cq)
+{
+	return ibv_destroy_cq(cq);
+}
+
+static int
+mlx5_glue_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
+		       void **cq_context)
+{
+	return ibv_get_cq_event(channel, cq, cq_context);
+}
+
+static void
+mlx5_glue_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq, nevents);
+}
+
+static struct ibv_rwq_ind_table *
+mlx5_glue_create_rwq_ind_table(struct ibv_context *context,
+			       struct ibv_rwq_ind_table_init_attr *init_attr)
+{
+	return ibv_create_rwq_ind_table(context, init_attr);
+}
+
+static int
+mlx5_glue_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table)
+{
+	return ibv_destroy_rwq_ind_table(rwq_ind_table);
+}
+
+static struct ibv_wq *
+mlx5_glue_create_wq(struct ibv_context *context,
+		    struct ibv_wq_init_attr *wq_init_attr)
+{
+	return ibv_create_wq(context, wq_init_attr);
+}
+
+static int
+mlx5_glue_destroy_wq(struct ibv_wq *wq)
+{
+	return ibv_destroy_wq(wq);
+}
+static int
+mlx5_glue_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr)
+{
+	return ibv_modify_wq(wq, wq_attr);
+}
+
+static struct ibv_flow *
+mlx5_glue_create_flow(struct ibv_qp *qp, struct ibv_flow_attr *flow)
+{
+	return ibv_create_flow(qp, flow);
+}
+
+static int
+mlx5_glue_destroy_flow(struct ibv_flow *flow_id)
+{
+	return ibv_destroy_flow(flow_id);
+}
+
+static struct ibv_qp *
+mlx5_glue_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
+{
+	return ibv_create_qp(pd, qp_init_attr);
+}
+
+static struct ibv_qp *
+mlx5_glue_create_qp_ex(struct ibv_context *context,
+		       struct ibv_qp_init_attr_ex *qp_init_attr_ex)
+{
+	return ibv_create_qp_ex(context, qp_init_attr_ex);
+}
+
+static int
+mlx5_glue_destroy_qp(struct ibv_qp *qp)
+{
+	return ibv_destroy_qp(qp);
+}
+
+static int
+mlx5_glue_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
+{
+	return ibv_modify_qp(qp, attr, attr_mask);
+}
+
+static struct ibv_mr *
+mlx5_glue_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access)
+{
+	return ibv_reg_mr(pd, addr, length, access);
+}
+
+static int
+mlx5_glue_dereg_mr(struct ibv_mr *mr)
+{
+	return ibv_dereg_mr(mr);
+}
+
+static struct ibv_counter_set *
+mlx5_glue_create_counter_set(struct ibv_context *context,
+			     struct ibv_counter_set_init_attr *init_attr)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)context;
+	(void)init_attr;
+	return NULL;
+#else
+	return ibv_create_counter_set(context, init_attr);
+#endif
+}
+
+static inline int
+mlx5_glue_destroy_counter_set(struct ibv_counter_set *cs)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)cs;
+	return -ENOTSUP;
+#else
+	return ibv_destroy_counter_set(cs);
+#endif
+}
+
+static void
+mlx5_glue_ack_async_event(struct ibv_async_event *event)
+{
+	ibv_ack_async_event(event);
+}
+
+static int
+mlx5_glue_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
+{
+	return ibv_get_async_event(context, event);
+}
+
+static const char *
+mlx5_glue_port_state_str(enum ibv_port_state port_state)
+{
+	return ibv_port_state_str(port_state);
+}
+
+static struct ibv_cq *
+mlx5_glue_cq_ex_to_cq(struct ibv_cq_ex *cq)
+{
+	return ibv_cq_ex_to_cq(cq);
+}
+
+static struct ibv_cq_ex *
+mlx5_glue_dv_create_cq(struct ibv_context *context,
+		       struct ibv_cq_init_attr_ex *cq_attr,
+		       struct mlx5dv_cq_init_attr *mlx5_cq_attr)
+{
+	return mlx5dv_create_cq(context, cq_attr, mlx5_cq_attr);
+}
+
+static int
+mlx5_glue_dv_query_device(struct ibv_context *ctx,
+			  struct mlx5dv_context *attrs_out)
+{
+	return mlx5dv_query_device(ctx, attrs_out);
+}
+
+static int
+mlx5_glue_dv_set_context_attr(struct ibv_context *ibv_ctx,
+			      enum mlx5dv_set_ctx_attr_type type, void *attr)
+{
+	return mlx5dv_set_context_attr(ibv_ctx, type, attr);
+}
+
+static int
+mlx5_glue_dv_init_obj(struct mlx5dv_obj *obj, uint64_t obj_type)
+{
+	return mlx5dv_init_obj(obj, obj_type);
+}
+
+const struct mlx5_glue *mlx5_glue = &(const struct mlx5_glue){
+	.fork_init = mlx5_glue_fork_init,
+	.alloc_pd = mlx5_glue_alloc_pd,
+	.dealloc_pd = mlx5_glue_dealloc_pd,
+	.get_device_list = mlx5_glue_get_device_list,
+	.free_device_list = mlx5_glue_free_device_list,
+	.open_device = mlx5_glue_open_device,
+	.close_device = mlx5_glue_close_device,
+	.query_device = mlx5_glue_query_device,
+	.query_device_ex = mlx5_glue_query_device_ex,
+	.query_port = mlx5_glue_query_port,
+	.create_comp_channel = mlx5_glue_create_comp_channel,
+	.destroy_comp_channel = mlx5_glue_destroy_comp_channel,
+	.create_cq = mlx5_glue_create_cq,
+	.destroy_cq = mlx5_glue_destroy_cq,
+	.get_cq_event = mlx5_glue_get_cq_event,
+	.ack_cq_events = mlx5_glue_ack_cq_events,
+	.create_rwq_ind_table = mlx5_glue_create_rwq_ind_table,
+	.destroy_rwq_ind_table = mlx5_glue_destroy_rwq_ind_table,
+	.create_wq = mlx5_glue_create_wq,
+	.destroy_wq = mlx5_glue_destroy_wq,
+	.modify_wq = mlx5_glue_modify_wq,
+	.create_flow = mlx5_glue_create_flow,
+	.destroy_flow = mlx5_glue_destroy_flow,
+	.create_qp = mlx5_glue_create_qp,
+	.create_qp_ex = mlx5_glue_create_qp_ex,
+	.destroy_qp = mlx5_glue_destroy_qp,
+	.modify_qp = mlx5_glue_modify_qp,
+	.reg_mr = mlx5_glue_reg_mr,
+	.dereg_mr = mlx5_glue_dereg_mr,
+	.create_counter_set = mlx5_glue_create_counter_set,
+	.destroy_counter_set = mlx5_glue_destroy_counter_set,
+	.ack_async_event = mlx5_glue_ack_async_event,
+	.get_async_event = mlx5_glue_get_async_event,
+	.port_state_str = mlx5_glue_port_state_str,
+	.cq_ex_to_cq = mlx5_glue_cq_ex_to_cq,
+	.dv_create_cq = mlx5_glue_dv_create_cq,
+	.dv_query_device = mlx5_glue_dv_query_device,
+	.dv_set_context_attr = mlx5_glue_dv_set_context_attr,
+	.dv_init_obj = mlx5_glue_dv_init_obj,
+};
diff --git a/drivers/net/mlx5/mlx5_glue.h b/drivers/net/mlx5/mlx5_glue.h
new file mode 100644
index 000000000..dc69b2895
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_glue.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox Technologies, Ltd.
+ */
+
+#ifndef MLX5_GLUE_H_
+#define MLX5_GLUE_H_
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+struct ibv_counter_set_init_attr {
+	int dummy;
+};
+struct ibv_counter_set {
+	int dummy;
+};
+#endif
+
+struct mlx5_glue {
+	int (*fork_init)(void);
+	struct ibv_pd *(*alloc_pd)(struct ibv_context *context);
+	int (*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_device **(*get_device_list)(int *num_devices);
+	void (*free_device_list)(struct ibv_device **list);
+	struct ibv_context *(*open_device)(struct ibv_device *device);
+	int (*close_device)(struct ibv_context *context);
+	int (*query_device)(struct ibv_context *context,
+			    struct ibv_device_attr *device_attr);
+	int (*query_device_ex)(struct ibv_context *context,
+			       const struct ibv_query_device_ex_input *input,
+			       struct ibv_device_attr_ex *attr);
+	int (*query_port)(struct ibv_context *context, uint8_t port_num,
+			  struct ibv_port_attr *port_attr);
+	struct ibv_comp_channel *(*create_comp_channel)
+		(struct ibv_context *context);
+	int (*destroy_comp_channel)(struct ibv_comp_channel *channel);
+	struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe,
+				    void *cq_context,
+				    struct ibv_comp_channel *channel,
+				    int comp_vector);
+	int (*destroy_cq)(struct ibv_cq *cq);
+	int (*get_cq_event)(struct ibv_comp_channel *channel,
+			    struct ibv_cq **cq, void **cq_context);
+	void (*ack_cq_events)(struct ibv_cq *cq, unsigned int nevents);
+	struct ibv_rwq_ind_table *(*create_rwq_ind_table)
+		(struct ibv_context *context,
+		 struct ibv_rwq_ind_table_init_attr *init_attr);
+	int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table);
+	struct ibv_wq *(*create_wq)(struct ibv_context *context,
+				    struct ibv_wq_init_attr *wq_init_attr);
+	int (*destroy_wq)(struct ibv_wq *wq);
+	int (*modify_wq)(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr);
+	struct ibv_flow *(*create_flow)(struct ibv_qp *qp,
+					struct ibv_flow_attr *flow);
+	int (*destroy_flow)(struct ibv_flow *flow_id);
+	struct ibv_qp *(*create_qp)(struct ibv_pd *pd,
+				    struct ibv_qp_init_attr *qp_init_attr);
+	struct ibv_qp *(*create_qp_ex)
+		(struct ibv_context *context,
+		 struct ibv_qp_init_attr_ex *qp_init_attr_ex);
+	int (*destroy_qp)(struct ibv_qp *qp);
+	int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+			 int attr_mask);
+	struct ibv_mr *(*reg_mr)(struct ibv_pd *pd, void *addr,
+				 size_t length, int access);
+	int (*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_counter_set *(*create_counter_set)
+		(struct ibv_context *context,
+		 struct ibv_counter_set_init_attr *init_attr);
+	int (*destroy_counter_set)(struct ibv_counter_set *cs);
+	void (*ack_async_event)(struct ibv_async_event *event);
+	int (*get_async_event)(struct ibv_context *context,
+			       struct ibv_async_event *event);
+	const char *(*port_state_str)(enum ibv_port_state port_state);
+	struct ibv_cq *(*cq_ex_to_cq)(struct ibv_cq_ex *cq);
+	struct ibv_cq_ex *(*dv_create_cq)
+		(struct ibv_context *context,
+		 struct ibv_cq_init_attr_ex *cq_attr,
+		 struct mlx5dv_cq_init_attr *mlx5_cq_attr);
+	int (*dv_query_device)(struct ibv_context *ctx_in,
+			       struct mlx5dv_context *attrs_out);
+	int (*dv_set_context_attr)(struct ibv_context *ibv_ctx,
+				   enum mlx5dv_set_ctx_attr_type type,
+				   void *attr);
+	int (*dv_init_obj)(struct mlx5dv_obj *obj, uint64_t obj_type);
+};
+
+const struct mlx5_glue *mlx5_glue;
+
+#endif /* MLX5_GLUE_H_ */
diff --git a/drivers/net/mlx5/mlx5_mr.c b/drivers/net/mlx5/mlx5_mr.c
index 33d037d28..28769d386 100644
--- a/drivers/net/mlx5/mlx5_mr.c
+++ b/drivers/net/mlx5/mlx5_mr.c
@@ -46,6 +46,7 @@
 
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
+#include "mlx5_glue.h"
 
 struct mlx5_check_mempool_data {
 	int ret;
@@ -315,8 +316,8 @@ priv_mr_new(struct priv *priv, struct rte_mempool *mp)
 	DEBUG("mempool %p using start=%p end=%p size=%zu for MR",
 	      (void *)mp, (void *)start, (void *)end,
 	      (size_t)(end - start));
-	mr->mr = ibv_reg_mr(priv->pd, (void *)start, end - start,
-			    IBV_ACCESS_LOCAL_WRITE);
+	mr->mr = mlx5_glue->reg_mr(priv->pd, (void *)start, end - start,
+				   IBV_ACCESS_LOCAL_WRITE);
 	mr->mp = mp;
 	mr->lkey = rte_cpu_to_be_32(mr->mr->lkey);
 	rte_atomic32_inc(&mr->refcnt);
@@ -372,7 +373,7 @@ priv_mr_release(struct priv *priv, struct mlx5_mr *mr)
 	DEBUG("Memory Region %p refcnt: %d",
 	      (void *)mr, rte_atomic32_read(&mr->refcnt));
 	if (rte_atomic32_dec_and_test(&mr->refcnt)) {
-		claim_zero(ibv_dereg_mr(mr->mr));
+		claim_zero(mlx5_glue->dereg_mr(mr->mr));
 		LIST_REMOVE(mr, next);
 		rte_free(mr);
 		return 0;
diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c
index 3c716b960..c7b884ab5 100644
--- a/drivers/net/mlx5/mlx5_rxq.c
+++ b/drivers/net/mlx5/mlx5_rxq.c
@@ -63,6 +63,7 @@
 #include "mlx5_utils.h"
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
+#include "mlx5_glue.h"
 
 /* Default RSS hash key also used for ConnectX-3. */
 uint8_t rss_hash_default_key[] = {
@@ -601,13 +602,13 @@ mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id)
 		ret = EINVAL;
 		goto exit;
 	}
-	ret = ibv_get_cq_event(rxq_ibv->channel, &ev_cq, &ev_ctx);
+	ret = mlx5_glue->get_cq_event(rxq_ibv->channel, &ev_cq, &ev_ctx);
 	if (ret || ev_cq != rxq_ibv->cq) {
 		ret = EINVAL;
 		goto exit;
 	}
 	rxq_data->cq_arm_sn++;
-	ibv_ack_cq_events(rxq_ibv->cq, 1);
+	mlx5_glue->ack_cq_events(rxq_ibv->cq, 1);
 exit:
 	if (rxq_ibv)
 		mlx5_priv_rxq_ibv_release(priv, rxq_ibv);
@@ -675,7 +676,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		}
 	}
 	if (rxq_ctrl->irq) {
-		tmpl->channel = ibv_create_comp_channel(priv->ctx);
+		tmpl->channel = mlx5_glue->create_comp_channel(priv->ctx);
 		if (!tmpl->channel) {
 			ERROR("%p: Comp Channel creation failure",
 			      (void *)rxq_ctrl);
@@ -703,8 +704,9 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	} else if (config->cqe_comp && rxq_data->hw_timestamp) {
 		DEBUG("Rx CQE compression is disabled for HW timestamp");
 	}
-	tmpl->cq = ibv_cq_ex_to_cq(mlx5dv_create_cq(priv->ctx, &attr.cq.ibv,
-						    &attr.cq.mlx5));
+	tmpl->cq = mlx5_glue->cq_ex_to_cq
+		(mlx5_glue->dv_create_cq(priv->ctx, &attr.cq.ibv,
+					 &attr.cq.mlx5));
 	if (tmpl->cq == NULL) {
 		ERROR("%p: CQ creation failure", (void *)rxq_ctrl);
 		goto error;
@@ -740,7 +742,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		attr.wq.comp_mask |= IBV_WQ_INIT_ATTR_FLAGS;
 	}
 #endif
-	tmpl->wq = ibv_create_wq(priv->ctx, &attr.wq);
+	tmpl->wq = mlx5_glue->create_wq(priv->ctx, &attr.wq);
 	if (tmpl->wq == NULL) {
 		ERROR("%p: WQ creation failure", (void *)rxq_ctrl);
 		goto error;
@@ -764,7 +766,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		.attr_mask = IBV_WQ_ATTR_STATE,
 		.wq_state = IBV_WQS_RDY,
 	};
-	ret = ibv_modify_wq(tmpl->wq, &mod);
+	ret = mlx5_glue->modify_wq(tmpl->wq, &mod);
 	if (ret) {
 		ERROR("%p: WQ state to IBV_WQS_RDY failed",
 		      (void *)rxq_ctrl);
@@ -774,7 +776,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	obj.cq.out = &cq_info;
 	obj.rwq.in = tmpl->wq;
 	obj.rwq.out = &rwq;
-	ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_RWQ);
+	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_RWQ);
 	if (ret != 0)
 		goto error;
 	if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
@@ -824,11 +826,11 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	return tmpl;
 error:
 	if (tmpl->wq)
-		claim_zero(ibv_destroy_wq(tmpl->wq));
+		claim_zero(mlx5_glue->destroy_wq(tmpl->wq));
 	if (tmpl->cq)
-		claim_zero(ibv_destroy_cq(tmpl->cq));
+		claim_zero(mlx5_glue->destroy_cq(tmpl->cq));
 	if (tmpl->channel)
-		claim_zero(ibv_destroy_comp_channel(tmpl->channel));
+		claim_zero(mlx5_glue->destroy_comp_channel(tmpl->channel));
 	if (tmpl->mr)
 		priv_mr_release(priv, tmpl->mr);
 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
@@ -894,10 +896,11 @@ mlx5_priv_rxq_ibv_release(struct priv *priv, struct mlx5_rxq_ibv *rxq_ibv)
 	      (void *)rxq_ibv, rte_atomic32_read(&rxq_ibv->refcnt));
 	if (rte_atomic32_dec_and_test(&rxq_ibv->refcnt)) {
 		rxq_free_elts(rxq_ibv->rxq_ctrl);
-		claim_zero(ibv_destroy_wq(rxq_ibv->wq));
-		claim_zero(ibv_destroy_cq(rxq_ibv->cq));
+		claim_zero(mlx5_glue->destroy_wq(rxq_ibv->wq));
+		claim_zero(mlx5_glue->destroy_cq(rxq_ibv->cq));
 		if (rxq_ibv->channel)
-			claim_zero(ibv_destroy_comp_channel(rxq_ibv->channel));
+			claim_zero(mlx5_glue->destroy_comp_channel
+				   (rxq_ibv->channel));
 		LIST_REMOVE(rxq_ibv, next);
 		rte_free(rxq_ibv);
 		return 0;
@@ -1225,13 +1228,13 @@ mlx5_priv_ind_table_ibv_new(struct priv *priv, uint16_t queues[],
 	/* Finalise indirection table. */
 	for (j = 0; i != (unsigned int)(1 << wq_n); ++i, ++j)
 		wq[i] = wq[j];
-	ind_tbl->ind_table = ibv_create_rwq_ind_table(
-		priv->ctx,
-		&(struct ibv_rwq_ind_table_init_attr){
+	ind_tbl->ind_table = mlx5_glue->create_rwq_ind_table
+		(priv->ctx,
+		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = wq_n,
 			.ind_tbl = wq,
 			.comp_mask = 0,
-		});
+		 });
 	if (!ind_tbl->ind_table)
 		goto error;
 	rte_atomic32_inc(&ind_tbl->refcnt);
@@ -1303,7 +1306,8 @@ mlx5_priv_ind_table_ibv_release(struct priv *priv,
 	DEBUG("%p: Indirection table %p: refcnt %d", (void *)priv,
 	      (void *)ind_tbl, rte_atomic32_read(&ind_tbl->refcnt));
 	if (rte_atomic32_dec_and_test(&ind_tbl->refcnt))
-		claim_zero(ibv_destroy_rwq_ind_table(ind_tbl->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table
+			   (ind_tbl->ind_table));
 	for (i = 0; i != ind_tbl->queues_n; ++i)
 		claim_nonzero(mlx5_priv_rxq_release(priv, ind_tbl->queues[i]));
 	if (!rte_atomic32_read(&ind_tbl->refcnt)) {
@@ -1370,9 +1374,9 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 		ind_tbl = mlx5_priv_ind_table_ibv_new(priv, queues, queues_n);
 	if (!ind_tbl)
 		return NULL;
-	qp = ibv_create_qp_ex(
-		priv->ctx,
-		&(struct ibv_qp_init_attr_ex){
+	qp = mlx5_glue->create_qp_ex
+		(priv->ctx,
+		 &(struct ibv_qp_init_attr_ex){
 			.qp_type = IBV_QPT_RAW_PACKET,
 			.comp_mask =
 				IBV_QP_INIT_ATTR_PD |
@@ -1386,7 +1390,7 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 			},
 			.rwq_ind_tbl = ind_tbl->ind_table,
 			.pd = priv->pd,
-		});
+		 });
 	if (!qp)
 		goto error;
 	hrxq = rte_calloc(__func__, 1, sizeof(*hrxq) + rss_key_len, 0);
@@ -1405,7 +1409,7 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 error:
 	mlx5_priv_ind_table_ibv_release(priv, ind_tbl);
 	if (qp)
-		claim_zero(ibv_destroy_qp(qp));
+		claim_zero(mlx5_glue->destroy_qp(qp));
 	return NULL;
 }
 
@@ -1473,7 +1477,7 @@ mlx5_priv_hrxq_release(struct priv *priv, struct mlx5_hrxq *hrxq)
 	DEBUG("%p: Hash Rx queue %p: refcnt %d", (void *)priv,
 	      (void *)hrxq, rte_atomic32_read(&hrxq->refcnt));
 	if (rte_atomic32_dec_and_test(&hrxq->refcnt)) {
-		claim_zero(ibv_destroy_qp(hrxq->qp));
+		claim_zero(mlx5_glue->destroy_qp(hrxq->qp));
 		mlx5_priv_ind_table_ibv_release(priv, hrxq->ind_table);
 		LIST_REMOVE(hrxq, next);
 		rte_free(hrxq);
diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c
index 65086d36f..bdaca5a00 100644
--- a/drivers/net/mlx5/mlx5_txq.c
+++ b/drivers/net/mlx5/mlx5_txq.c
@@ -59,6 +59,7 @@
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
 
 /**
  * Allocate TX queue elements.
@@ -432,7 +433,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		((desc / MLX5_TX_COMP_THRESH) - 1) : 1;
 	if (is_empw_burst_func(tx_pkt_burst))
 		cqe_n += MLX5_TX_COMP_THRESH_INLINE_DIV;
-	tmpl.cq = ibv_create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
+	tmpl.cq = mlx5_glue->create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
 	if (tmpl.cq == NULL) {
 		ERROR("%p: CQ creation failure", (void *)txq_ctrl);
 		goto error;
@@ -473,7 +474,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		attr.init.max_tso_header = txq_ctrl->max_tso_header;
 		attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
 	}
-	tmpl.qp = ibv_create_qp_ex(priv->ctx, &attr.init);
+	tmpl.qp = mlx5_glue->create_qp_ex(priv->ctx, &attr.init);
 	if (tmpl.qp == NULL) {
 		ERROR("%p: QP creation failure", (void *)txq_ctrl);
 		goto error;
@@ -484,7 +485,8 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		/* Primary port number. */
 		.port_num = priv->port
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, (IBV_QP_STATE | IBV_QP_PORT));
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod,
+				   (IBV_QP_STATE | IBV_QP_PORT));
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_INIT failed", (void *)txq_ctrl);
 		goto error;
@@ -492,13 +494,13 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	attr.mod = (struct ibv_qp_attr){
 		.qp_state = IBV_QPS_RTR
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_RTR failed", (void *)txq_ctrl);
 		goto error;
 	}
 	attr.mod.qp_state = IBV_QPS_RTS;
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_RTS failed", (void *)txq_ctrl);
 		goto error;
@@ -513,7 +515,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	obj.cq.out = &cq_info;
 	obj.qp.in = tmpl.qp;
 	obj.qp.out = &qp;
-	ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
+	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
 	if (ret != 0)
 		goto error;
 	if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
@@ -553,9 +555,9 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	return txq_ibv;
 error:
 	if (tmpl.cq)
-		claim_zero(ibv_destroy_cq(tmpl.cq));
+		claim_zero(mlx5_glue->destroy_cq(tmpl.cq));
 	if (tmpl.qp)
-		claim_zero(ibv_destroy_qp(tmpl.qp));
+		claim_zero(mlx5_glue->destroy_qp(tmpl.qp));
 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
 	return NULL;
 }
@@ -609,8 +611,8 @@ mlx5_priv_txq_ibv_release(struct priv *priv, struct mlx5_txq_ibv *txq_ibv)
 	DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
 	      (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
 	if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
-		claim_zero(ibv_destroy_qp(txq_ibv->qp));
-		claim_zero(ibv_destroy_cq(txq_ibv->cq));
+		claim_zero(mlx5_glue->destroy_qp(txq_ibv->qp));
+		claim_zero(mlx5_glue->destroy_cq(txq_ibv->cq));
 		LIST_REMOVE(txq_ibv, next);
 		rte_free(txq_ibv);
 		return 0;
diff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c
index d51dbe941..f55e5e020 100644
--- a/drivers/net/mlx5/mlx5_vlan.c
+++ b/drivers/net/mlx5/mlx5_vlan.c
@@ -36,12 +36,23 @@
 #include <assert.h>
 #include <stdint.h>
 
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
 #include <rte_ethdev_driver.h>
 #include <rte_common.h>
 
 #include "mlx5_utils.h"
 #include "mlx5.h"
 #include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
 
 /**
  * DPDK callback to configure a VLAN filter.
@@ -138,7 +149,7 @@ priv_vlan_strip_queue_set(struct priv *priv, uint16_t idx, int on)
 		.flags = vlan_offloads,
 	};
 
-	err = ibv_modify_wq(rxq_ctrl->ibv->wq, &mod);
+	err = mlx5_glue->modify_wq(rxq_ctrl->ibv->wq, &mod);
 	if (err) {
 		ERROR("%p: failed to modified stripping mode: %s",
 		      (void *)priv, strerror(err));
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v2 4/4] net/mlx5: spawn rdma-core dependency plug-in
  2018-01-26 14:18 ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
                     ` (2 preceding siblings ...)
  2018-01-26 14:19   ` [PATCH v2 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
@ 2018-01-26 14:19   ` Adrien Mazarguil
  2018-01-26 15:58   ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Nélio Laranjeiro
  2018-01-29 17:19   ` [PATCH v3 " Adrien Mazarguil
  5 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-26 14:19 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

When mlx5 is not compiled directly as an independent shared object (e.g.
CONFIG_RTE_BUILD_SHARED_LIB not enabled for performance reasons), DPDK
applications inherit its dependencies on libibverbs and libmlx5 through
rte.app.mk.

This is an issue both when DPDK is delivered as a binary package (Linux
distributions) and for end users because rdma-core then propagates as a
mandatory dependency for everything.

Application writers relying on binary DPDK packages are not necessarily
aware of this fact and may end up delivering packages with broken
dependencies.

This patch therefore introduces an intermediate internal plug-in
hard-linked with rdma-core (to preserve symbol versioning) loaded by the
PMD through dlopen(), so that a missing rdma-core does not cause unresolved
symbols, allowing applications to start normally.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 config/common_base        |  1 +
 doc/guides/nics/mlx5.rst  | 13 +++++++
 drivers/net/mlx5/Makefile | 41 ++++++++++++++++++++++
 drivers/net/mlx5/mlx5.c   | 79 ++++++++++++++++++++++++++++++++++++++++++
 mk/rte.app.mk             |  4 +++
 5 files changed, 138 insertions(+)

diff --git a/config/common_base b/config/common_base
index f29f9e3a0..5564576fc 100644
--- a/config/common_base
+++ b/config/common_base
@@ -306,6 +306,7 @@ CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8
 #
 CONFIG_RTE_LIBRTE_MLX5_PMD=n
 CONFIG_RTE_LIBRTE_MLX5_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=y
 CONFIG_RTE_LIBRTE_MLX5_TX_MP_CACHE=8
 
 #
diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index 2e6d1e45a..c8bd02112 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -159,6 +159,19 @@ These options can be modified in the ``.config`` file.
 
   Toggle compilation of librte_pmd_mlx5 itself.
 
+- ``CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS`` (default **y**)
+
+  Build PMD with additional code to make it loadable without hard
+  dependencies on **libibverbs** nor **libmlx5**, which may not be installed
+  on the target system.
+
+  In this mode, their presence is still required for it to run properly,
+  however their absence won't prevent a DPDK application from starting (with
+  ``CONFIG_RTE_BUILD_SHARED_LIB`` disabled) and they won't show up as
+  missing with ``ldd(1)``.
+
+  This option has no performance impact.
+
 - ``CONFIG_RTE_LIBRTE_MLX5_DEBUG`` (default **n**)
 
   Toggle debugging code and stricter compilation flags. Enabling this option
diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index bdec30692..761e60afd 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -53,7 +53,11 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue_lib.c
+else
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
+endif
 
 # Basic CFLAGS.
 CFLAGS += -O3
@@ -65,7 +69,12 @@ CFLAGS += -D_DEFAULT_SOURCE
 CFLAGS += -D_XOPEN_SOURCE=600
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -Wno-strict-prototypes
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+CFLAGS_mlx5_glue.o += -fPIC
+LDLIBS += -ldl
+else
 LDLIBS += -libverbs -lmlx5
+endif
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
@@ -158,7 +167,39 @@ mlx5_autoconf.h: mlx5_autoconf.h.new
 
 $(SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD):.c=.o): mlx5_autoconf.h
 
+# Generate dependency plug-in for rdma-core when the PMD must not be linked
+# directly, so that applications do not inherit this dependency.
+
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+
+mlx5_glue_lib.c: mlx5_glue_lib.so
+	$Q printf '#include <stddef.h>\n' > $@
+	$Q printf '#include <stdint.h>\n\n' >> $@
+	$Q printf 'const uint8_t mlx5_glue_lib[][16] = {\n' >> $@
+	$Q od -vt x1 $< | \
+	sed -ne '/^[[:xdigit:]]\{1,\}/{' \
+		-e 's///;' \
+		-e '/^$$/d; ' \
+		-e 's/[[:space:]]*$$//;' \
+		-e 's/[[:space:]]\{1,\}/\\x/g;' \
+		-e 's/^/	"/;' \
+		-e 's/$$/",/;' \
+		-e 'p;' \
+		-e '}' >> $@
+	$Q printf '};\n\n' >> $@
+	$Q printf 'const size_t mlx5_glue_lib_size = %u;\n' \
+		$$(wc -c < $<) >> $@
+
+mlx5_glue_lib.so: mlx5_glue.o
+	$Q $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) \
+		-s -shared -o $@ $< -libverbs -lmlx5
+
+mlx5_glue.o: mlx5_autoconf.h
+
+endif
+
 clean_mlx5: FORCE
 	$Q rm -f -- mlx5_autoconf.h mlx5_autoconf.h.new
+	$Q rm -f -- mlx5_glue.o mlx5_glue_lib.*
 
 clean: clean_mlx5
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index b911d0ad4..05c9768d0 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -35,6 +35,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>
+#include <dlfcn.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -57,6 +58,7 @@
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
 #include <rte_common.h>
+#include <rte_config.h>
 #include <rte_eal_memconfig.h>
 #include <rte_kvargs.h>
 
@@ -1075,6 +1077,78 @@ static struct rte_pci_driver mlx5_driver = {
 	.drv_flags = RTE_PCI_DRV_INTR_LSC | RTE_PCI_DRV_INTR_RMV,
 };
 
+#ifdef RTE_LIBRTE_MLX5_DLOPEN_DEPS
+
+extern const uint8_t mlx5_glue_lib[][16];
+extern const size_t mlx5_glue_lib_size;
+
+/**
+ * Initialization routine for run-time dependency on rdma-core.
+ */
+static int
+mlx5_glue_init(void)
+{
+	char file[] = "/tmp/" MLX5_DRIVER_NAME "_XXXXXX";
+	int fd = mkstemp(file);
+	size_t off = 0;
+	void *handle = NULL;
+	void **sym;
+	const char *dlmsg;
+
+	if (fd == -1) {
+		rte_errno = errno;
+		goto glue_error;
+	}
+	while (off != mlx5_glue_lib_size) {
+		ssize_t ret;
+
+		ret = write(fd, (const uint8_t *)mlx5_glue_lib + off,
+			    mlx5_glue_lib_size - off);
+		if (ret == -1) {
+			if (errno != EINTR) {
+				rte_errno = errno;
+				goto glue_error;
+			}
+			ret = 0;
+		}
+		off += ret;
+	}
+	close(fd);
+	fd = -1;
+	handle = dlopen(file, RTLD_LAZY);
+	unlink(file);
+	if (!handle) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot load glue library: %s", dlmsg);
+		goto glue_error;
+	}
+	sym = dlsym(handle, "mlx5_glue");
+	if (!sym || !*sym) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot resolve glue symbol: %s", dlmsg);
+		goto glue_error;
+	}
+	mlx5_glue = *sym;
+	return 0;
+glue_error:
+	if (handle)
+		dlclose(handle);
+	if (fd != -1) {
+		close(fd);
+		unlink(file);
+	}
+	ERROR("cannot initialize PMD due to missing run-time"
+	      " dependency on rdma-core libraries (libibverbs,"
+	      " libmlx5)");
+	return -rte_errno;
+}
+
+#endif
+
 /**
  * Driver initialization routine.
  */
@@ -1094,6 +1168,11 @@ rte_mlx5_pmd_init(void)
 	/* Match the size of Rx completion entry to the size of a cacheline. */
 	if (RTE_CACHE_LINE_SIZE == 128)
 		setenv("MLX5_CQE_SIZE", "128", 0);
+#ifdef RTE_LIBRTE_MLX5_DLOPEN_DEPS
+	if (mlx5_glue_init())
+		return;
+	assert(mlx5_glue);
+#endif
 	mlx5_glue->fork_init();
 	rte_pci_register(&mlx5_driver);
 }
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index fdbe36630..88f626049 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -148,7 +148,11 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -ldl
 else
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs -lmlx4
 endif
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -ldl
+else
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs -lmlx5
+endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time
  2018-01-26 14:18 ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
                     ` (3 preceding siblings ...)
  2018-01-26 14:19   ` [PATCH v2 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-26 15:58   ` Nélio Laranjeiro
  2018-01-29 17:19   ` [PATCH v3 " Adrien Mazarguil
  5 siblings, 0 replies; 31+ messages in thread
From: Nélio Laranjeiro @ 2018-01-26 15:58 UTC (permalink / raw)
  To: Adrien Mazarguil; +Cc: Shahaf Shuler, dev, Marcelo Ricardo Leitner

On Fri, Jan 26, 2018 at 03:18:55PM +0100, Adrien Mazarguil wrote:
> A problem encountered with Mellanox PMDs and frequently reported by DPDK
> application developers and Linux distribution package maintainers is their
> dependency on rdma-core components, namely libibverbs, libmlx4, and libmlx5.
> 
> For best performance in applications, DPDK is normally built as a collection
> of library archives (.a files), whose external dependencies are inherited
> through rte.app.mk during link.
> 
> When these PMDs are built-in, any binary DPDK package, whether DPDK itself
> or derived applications, always have to pull rdma-core. This dependency is
> not obvious and may be missed during the packaging of any intermediate layer
> between DPDK itself and the end application.
> 
> While still required during compilation, this series trades this hard
> dependency for an optional one, dynamically loaded at run-time through
> dlopen().
> 
> It supersedes Shachar's previous work on the same topic [1] using a
> different approach in order to preserve symbol versioning and address
> the remaining issues.
> 
> [1] http://dpdk.org/ml/archives/dev/2017-December/085090.html
> 
> v2 changes:
> 
> - Rebased on dpdk-next-net-mlx.
> - Rely on CONFIG_RTE_LIBRTE_MLX[45]_DLOPEN_DEPS instead of
>   CONFIG_RTE_BUILD_SHARED_LIB to enable this mode, so it can be overridden
>   if necessary.
> - Fixed -lmlx5 -libibverbs leftovers in rte.app.mk.
> - Minor fixes for indentation and unnecessary includes in mlx5.
> 
> Adrien Mazarguil (3):
>   net/mlx4: move rdma-core calls to separate file
>   net/mlx4: spawn rdma-core dependency plug-in
>   net/mlx5: spawn rdma-core dependency plug-in
> 
> Nelio Laranjeiro (1):
>   net/mlx5: move rdma-core calls to separate file
> 
>  config/common_base             |   2 +
>  doc/guides/nics/mlx4.rst       |  13 ++
>  doc/guides/nics/mlx5.rst       |  13 ++
>  drivers/net/mlx4/Makefile      |  42 +++++
>  drivers/net/mlx4/mlx4.c        | 115 +++++++++++--
>  drivers/net/mlx4/mlx4_ethdev.c |   3 +-
>  drivers/net/mlx4/mlx4_flow.c   |  32 ++--
>  drivers/net/mlx4/mlx4_glue.c   | 275 ++++++++++++++++++++++++++++++
>  drivers/net/mlx4/mlx4_glue.h   |  80 +++++++++
>  drivers/net/mlx4/mlx4_intr.c   |  10 +-
>  drivers/net/mlx4/mlx4_mr.c     |   7 +-
>  drivers/net/mlx4/mlx4_rxq.c    |  53 +++---
>  drivers/net/mlx4/mlx4_txq.c    |  17 +-
>  drivers/net/mlx5/Makefile      |  42 +++++
>  drivers/net/mlx5/mlx5.c        | 123 +++++++++++---
>  drivers/net/mlx5/mlx5_ethdev.c |   7 +-
>  drivers/net/mlx5/mlx5_flow.c   |  92 +++++------
>  drivers/net/mlx5/mlx5_glue.c   | 321 ++++++++++++++++++++++++++++++++++++
>  drivers/net/mlx5/mlx5_glue.h   |  99 +++++++++++
>  drivers/net/mlx5/mlx5_mr.c     |   7 +-
>  drivers/net/mlx5/mlx5_rxq.c    |  54 +++---
>  drivers/net/mlx5/mlx5_txq.c    |  22 +--
>  drivers/net/mlx5/mlx5_vlan.c   |  13 +-
>  mk/rte.app.mk                  |   8 +
>  24 files changed, 1265 insertions(+), 185 deletions(-)
>  create mode 100644 drivers/net/mlx4/mlx4_glue.c
>  create mode 100644 drivers/net/mlx4/mlx4_glue.h
>  create mode 100644 drivers/net/mlx5/mlx5_glue.c
>  create mode 100644 drivers/net/mlx5/mlx5_glue.h
> 
> -- 
> 2.11.0

Acked-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>

-- 
Nélio Laranjeiro
6WIND

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v2 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-26 14:19   ` [PATCH v2 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-27 15:03     ` Marcelo Ricardo Leitner
  2018-01-28  9:04       ` Shahaf Shuler
  0 siblings, 1 reply; 31+ messages in thread
From: Marcelo Ricardo Leitner @ 2018-01-27 15:03 UTC (permalink / raw)
  To: Adrien Mazarguil; +Cc: Shahaf Shuler, Nelio Laranjeiro, dev

On Fri, Jan 26, 2018 at 03:19:00PM +0100, Adrien Mazarguil wrote:
...
> +static int
> +mlx4_glue_init(void)
> +{
> +	char file[] = "/tmp/" MLX4_DRIVER_NAME "_XXXXXX";
> +	int fd = mkstemp(file);
...
> +	while (off != mlx4_glue_lib_size) {
> +		ssize_t ret;
> +
> +		ret = write(fd, (const uint8_t *)mlx4_glue_lib + off,
> +			    mlx4_glue_lib_size - off);
> +		if (ret == -1) {
> +			if (errno != EINTR) {
> +				rte_errno = errno;
> +				goto glue_error;
> +			}
> +			ret = 0;
> +		}
> +		off += ret;
> +	}
> +	close(fd);
> +	fd = -1;
> +	handle = dlopen(file, RTLD_LAZY);
> +	unlink(file);

This is a potential security issue. There are no guarantees that the
file dlopen() will open is the file that was just written above. It
could have been changed by something else in between.

  Marcelo

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v2 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-27 15:03     ` Marcelo Ricardo Leitner
@ 2018-01-28  9:04       ` Shahaf Shuler
  2018-01-28 11:17         ` Marcelo Ricardo Leitner
  0 siblings, 1 reply; 31+ messages in thread
From: Shahaf Shuler @ 2018-01-28  9:04 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner, Adrien Mazarguil; +Cc: Nélio Laranjeiro, dev

Hi Marcelo, 

Saturday, January 27, 2018 5:03 PM, Marcelo Ricardo Leitner:
> On Fri, Jan 26, 2018 at 03:19:00PM +0100, Adrien Mazarguil wrote:
> ...
> > +static int
> > +mlx4_glue_init(void)
> > +{
> > +	char file[] = "/tmp/" MLX4_DRIVER_NAME "_XXXXXX";
> > +	int fd = mkstemp(file);
> ...
> > +	while (off != mlx4_glue_lib_size) {
> > +		ssize_t ret;
> > +
> > +		ret = write(fd, (const uint8_t *)mlx4_glue_lib + off,
> > +			    mlx4_glue_lib_size - off);
> > +		if (ret == -1) {
> > +			if (errno != EINTR) {
> > +				rte_errno = errno;
> > +				goto glue_error;
> > +			}
> > +			ret = 0;
> > +		}
> > +		off += ret;
> > +	}
> > +	close(fd);
> > +	fd = -1;
> > +	handle = dlopen(file, RTLD_LAZY);
> > +	unlink(file);
> 
> This is a potential security issue. There are no guarantees that the file
> dlopen() will open is the file that was just written above. It could have been
> changed by something else in between.

Can you further explain what are the potential risks you want to protect from?
I think this issue is not different from regular file protection under Linux. 

If the DPDK process ran by root, then this approach is no less secure than the previous version of the patches that dlopen the /usr/lib/libibverbs.so and /usr/lib/libmlx5.so.  root can also change them before the dlopen. 
In fact in terms of security, root user can intentionally damage the system in many other ways.

If the DPDK process ran by regular user X, then the only users that are allowed to modify the file created are user X and possibly root. Other users will not have write permission to it.
if the same user change this temporary file, then it damages itself only, as the DPDK process run by it will probably won't lunch. 


> 
>   Marcelo

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v2 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-28  9:04       ` Shahaf Shuler
@ 2018-01-28 11:17         ` Marcelo Ricardo Leitner
  2018-01-28 11:46           ` Shahaf Shuler
  0 siblings, 1 reply; 31+ messages in thread
From: Marcelo Ricardo Leitner @ 2018-01-28 11:17 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Adrien Mazarguil, Nélio Laranjeiro, dev

Hi Shahaf,

On Sun, Jan 28, 2018 at 09:04:36AM +0000, Shahaf Shuler wrote:
> Hi Marcelo, 
> 
> Saturday, January 27, 2018 5:03 PM, Marcelo Ricardo Leitner:
> > On Fri, Jan 26, 2018 at 03:19:00PM +0100, Adrien Mazarguil wrote:
> > ...
> > > +static int
> > > +mlx4_glue_init(void)
> > > +{
> > > +	char file[] = "/tmp/" MLX4_DRIVER_NAME "_XXXXXX";
> > > +	int fd = mkstemp(file);
> > ...
> > > +	while (off != mlx4_glue_lib_size) {
> > > +		ssize_t ret;
> > > +
> > > +		ret = write(fd, (const uint8_t *)mlx4_glue_lib + off,
> > > +			    mlx4_glue_lib_size - off);
> > > +		if (ret == -1) {
> > > +			if (errno != EINTR) {
> > > +				rte_errno = errno;
> > > +				goto glue_error;
> > > +			}
> > > +			ret = 0;
> > > +		}
> > > +		off += ret;
> > > +	}
> > > +	close(fd);
> > > +	fd = -1;
> > > +	handle = dlopen(file, RTLD_LAZY);
> > > +	unlink(file);
> > 
> > This is a potential security issue. There are no guarantees that the file
> > dlopen() will open is the file that was just written above. It could have been
> > changed by something else in between.
> 
> Can you further explain what are the potential risks you want to
> protect from?

It is different in some aspects,

> I think this issue is not different from regular file protection
> under Linux. 

in regular files we can ensure the right selinux contexts and
permissions are set, which is not the case here.

/usr could be even mounted as R/O and files just loaded from there,
while with this approach you're allocating a new file on a temporary
dir, which potentially is using extra RAM memory to store it and then
load it.

> 
> If the DPDK process ran by root, then this approach is no less
> secure than the previous version of the patches that dlopen the
> /usr/lib/libibverbs.so and /usr/lib/libmlx5.so.  root can also
> change them before the dlopen. 

Maybe, and though that probably would leave traces in the system that
that happened.

> In fact in terms of security, root user can intentionally damage the
> system in many other ways.

And a SELinux (mis)configuration could grant (unexpected) write access
to the file for some other, non-root, user.

> 
> If the DPDK process ran by regular user X, then the only users that
> are allowed to modify the file created are user X and possibly root.
> Other users will not have write permission to it.
> if the same user change this temporary file, then it damages itself
> only, as the DPDK process run by it will probably won't lunch. 

Let's work this from the other PoV: why embed the library in dpdk
binary? How is it any more stable than regular libraries?

If it's just to hide it from rpm dependency generator, there is
probably a cleaner way to do it. For example, packaging the lib in a
sub-package, or maybe some more tricky rpm macro. 

  Marcelo

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v2 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-28 11:17         ` Marcelo Ricardo Leitner
@ 2018-01-28 11:46           ` Shahaf Shuler
  0 siblings, 0 replies; 31+ messages in thread
From: Shahaf Shuler @ 2018-01-28 11:46 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner; +Cc: Adrien Mazarguil, Nélio Laranjeiro, dev

Sunday, January 28, 2018 1:18 PM, Marcelo Ricardo Leitner:
> Hi Shahaf,
> 
> On Sun, Jan 28, 2018 at 09:04:36AM +0000, Shahaf Shuler wrote:
> > Hi Marcelo,
> >
> > Saturday, January 27, 2018 5:03 PM, Marcelo Ricardo Leitner:
> > > On Fri, Jan 26, 2018 at 03:19:00PM +0100, Adrien Mazarguil wrote:
> > > ...
> > > > +static int
> > > > +mlx4_glue_init(void)
> > > > +{
> > > > +	char file[] = "/tmp/" MLX4_DRIVER_NAME "_XXXXXX";
> > > > +	int fd = mkstemp(file);
> > > ...
> > > > +	while (off != mlx4_glue_lib_size) {
> > > > +		ssize_t ret;
> > > > +
> > > > +		ret = write(fd, (const uint8_t *)mlx4_glue_lib + off,
> > > > +			    mlx4_glue_lib_size - off);
> > > > +		if (ret == -1) {
> > > > +			if (errno != EINTR) {
> > > > +				rte_errno = errno;
> > > > +				goto glue_error;
> > > > +			}
> > > > +			ret = 0;
> > > > +		}
> > > > +		off += ret;
> > > > +	}
> > > > +	close(fd);
> > > > +	fd = -1;
> > > > +	handle = dlopen(file, RTLD_LAZY);
> > > > +	unlink(file);
> > >
> > > This is a potential security issue. There are no guarantees that the
> > > file
> > > dlopen() will open is the file that was just written above. It could
> > > have been changed by something else in between.
> >
> > Can you further explain what are the potential risks you want to
> > protect from?
> 
> It is different in some aspects,
> 
> > I think this issue is not different from regular file protection under
> > Linux.
> 
> in regular files we can ensure the right selinux contexts and permissions are
> set, which is not the case here.
> 
> /usr could be even mounted as R/O and files just loaded from there, while
> with this approach you're allocating a new file on a temporary dir, which
> potentially is using extra RAM memory to store it and then load it.

So the issue is with the absolute path that contains the temporary file or with the concept of embedding the library inside the DPDK binary? 

> 
> >
> > If the DPDK process ran by root, then this approach is no less secure
> > than the previous version of the patches that dlopen the
> > /usr/lib/libibverbs.so and /usr/lib/libmlx5.so.  root can also change
> > them before the dlopen.
> 
> Maybe, and though that probably would leave traces in the system that that
> happened.
> 
> > In fact in terms of security, root user can intentionally damage the
> > system in many other ways.
> 
> And a SELinux (mis)configuration could grant (unexpected) write access to
> the file for some other, non-root, user.
> 
> >
> > If the DPDK process ran by regular user X, then the only users that
> > are allowed to modify the file created are user X and possibly root.
> > Other users will not have write permission to it.
> > if the same user change this temporary file, then it damages itself
> > only, as the DPDK process run by it will probably won't lunch.
> 
> Let's work this from the other PoV: why embed the library in dpdk binary?
> How is it any more stable than regular libraries?

The main reason is not to force the DPDK user to install the DPDK.
Using the approach suggest on this commit, DPDK user can just "make" DPDK and that is it. 
When the DPDK application starts, it spits a temporary file which happens to be usable with dlopen() and hard-linked with libibverbs and libmlx[45] and once loaded in memory, removes it from the file system.
 
dlopen the library itself will require the library to be in some well-known location. 

> 
> If it's just to hide it from rpm dependency generator, there is probably a
> cleaner way to do it. For example, packaging the lib in a sub-package, or
> maybe some more tricky rpm macro.

Do you see it as a preferred solution ? Having the glue lib included in rpms and install it per demand in case the binary execution failed?

> 
>   Marcelo

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v3 0/4] net/mlx: make rdma-core optional at run-time
  2018-01-26 14:18 ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
                     ` (4 preceding siblings ...)
  2018-01-26 15:58   ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Nélio Laranjeiro
@ 2018-01-29 17:19   ` Adrien Mazarguil
  2018-01-29 17:19     ` [PATCH v3 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
                       ` (4 more replies)
  5 siblings, 5 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-29 17:19 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

A problem encountered with Mellanox PMDs and frequently reported by DPDK
application developers and Linux distribution package maintainers is their
dependency on rdma-core components, namely libibverbs, libmlx4, and libmlx5.

For best performance in applications, DPDK is normally built as a collection
of library archives (.a files), whose external dependencies are inherited
through rte.app.mk during link.

When these PMDs are built-in, any binary DPDK package, whether DPDK itself
or derived applications, always have to pull rdma-core. This dependency is
not obvious and may be missed during the packaging of any intermediate layer
between DPDK itself and the end application.

While still required during compilation, this series trades this hard
dependency for an optional one, dynamically loaded at run-time through
dlopen().

It supersedes Shachar's previous work on the same topic [1] using a
different approach in order to preserve symbol versioning and address
the remaining issues.

[1] http://dpdk.org/ml/archives/dev/2017-December/085090.html

v3 changes:

- Rebased on dpdk-next-net-mlx.
- Modified patches to generate mlx4/mlx5 glue objects as independent
  libraries to install on the target system (they are not generated at run
  time anymore) in order to address security concerns.
- As a consequence, glue libraries generation is now disabled by default and
  binary distributions must take care of properly packaging them if enabled.

v2 changes:

- Rebased on dpdk-next-net-mlx.
- Rely on CONFIG_RTE_LIBRTE_MLX[45]_DLOPEN_DEPS instead of
  CONFIG_RTE_BUILD_SHARED_LIB to enable this mode, so it can be overridden
  if necessary.
- Fixed -lmlx5 -libibverbs leftovers in rte.app.mk.
- Minor fixes for indentation and unnecessary includes in mlx5.

Adrien Mazarguil (3):
  net/mlx4: move rdma-core calls to separate file
  net/mlx4: spawn rdma-core dependency plug-in
  net/mlx5: spawn rdma-core dependency plug-in

Nelio Laranjeiro (1):
  net/mlx5: move rdma-core calls to separate file

 config/common_base             |   2 +
 doc/guides/nics/mlx4.rst       |  13 ++
 doc/guides/nics/mlx5.rst       |  13 ++
 drivers/net/mlx4/Makefile      |  30 ++++
 drivers/net/mlx4/mlx4.c        |  84 ++++++++--
 drivers/net/mlx4/mlx4_ethdev.c |   3 +-
 drivers/net/mlx4/mlx4_flow.c   |  32 ++--
 drivers/net/mlx4/mlx4_glue.c   | 275 ++++++++++++++++++++++++++++++
 drivers/net/mlx4/mlx4_glue.h   |  80 +++++++++
 drivers/net/mlx4/mlx4_intr.c   |  10 +-
 drivers/net/mlx4/mlx4_mr.c     |   7 +-
 drivers/net/mlx4/mlx4_rxq.c    |  53 +++---
 drivers/net/mlx4/mlx4_txq.c    |  17 +-
 drivers/net/mlx5/Makefile      |  30 ++++
 drivers/net/mlx5/mlx5.c        |  92 ++++++++---
 drivers/net/mlx5/mlx5_ethdev.c |   7 +-
 drivers/net/mlx5/mlx5_flow.c   |  92 +++++------
 drivers/net/mlx5/mlx5_glue.c   | 321 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h   |  99 +++++++++++
 drivers/net/mlx5/mlx5_mr.c     |   7 +-
 drivers/net/mlx5/mlx5_rxq.c    |  54 +++---
 drivers/net/mlx5/mlx5_txq.c    |  22 +--
 drivers/net/mlx5/mlx5_vlan.c   |  13 +-
 mk/rte.app.mk                  |   8 +
 24 files changed, 1179 insertions(+), 185 deletions(-)
 create mode 100644 drivers/net/mlx4/mlx4_glue.c
 create mode 100644 drivers/net/mlx4/mlx4_glue.h
 create mode 100644 drivers/net/mlx5/mlx5_glue.c
 create mode 100644 drivers/net/mlx5/mlx5_glue.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v3 1/4] net/mlx4: move rdma-core calls to separate file
  2018-01-29 17:19   ` [PATCH v3 " Adrien Mazarguil
@ 2018-01-29 17:19     ` Adrien Mazarguil
  2018-01-29 17:19     ` [PATCH v3 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-29 17:19 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

This lays the groundwork for externalizing rdma-core as an optional
run-time dependency instead of a mandatory one.

No functional change.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
---
 drivers/net/mlx4/Makefile      |   1 +
 drivers/net/mlx4/mlx4.c        |  35 ++---
 drivers/net/mlx4/mlx4_ethdev.c |   3 +-
 drivers/net/mlx4/mlx4_flow.c   |  32 +++--
 drivers/net/mlx4/mlx4_glue.c   | 275 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx4/mlx4_glue.h   |  80 +++++++++++
 drivers/net/mlx4/mlx4_intr.c   |  10 +-
 drivers/net/mlx4/mlx4_mr.c     |   7 +-
 drivers/net/mlx4/mlx4_rxq.c    |  53 +++----
 drivers/net/mlx4/mlx4_txq.c    |  17 +--
 10 files changed, 440 insertions(+), 73 deletions(-)

diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1f95e0df9..1d33c38ed 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -38,6 +38,7 @@ LIB = librte_pmd_mlx4.a
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_intr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxq.c
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 952dae08a..f304359bb 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -67,6 +67,7 @@
 #include <rte_mbuf.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -218,8 +219,8 @@ mlx4_dev_close(struct rte_eth_dev *dev)
 		mlx4_tx_queue_release(dev->data->tx_queues[i]);
 	if (priv->pd != NULL) {
 		assert(priv->ctx != NULL);
-		claim_zero(ibv_dealloc_pd(priv->pd));
-		claim_zero(ibv_close_device(priv->ctx));
+		claim_zero(mlx4_glue->dealloc_pd(priv->pd));
+		claim_zero(mlx4_glue->close_device(priv->ctx));
 	} else
 		assert(priv->ctx == NULL);
 	mlx4_intr_uninstall(priv);
@@ -436,7 +437,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 	(void)pci_drv;
 	assert(pci_drv == &mlx4_driver);
-	list = ibv_get_device_list(&i);
+	list = mlx4_glue->get_device_list(&i);
 	if (list == NULL) {
 		rte_errno = errno;
 		assert(rte_errno);
@@ -465,12 +466,12 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		      PCI_DEVICE_ID_MELLANOX_CONNECTX3VF);
 		INFO("PCI information matches, using device \"%s\" (VF: %s)",
 		     list[i]->name, (vf ? "true" : "false"));
-		attr_ctx = ibv_open_device(list[i]);
+		attr_ctx = mlx4_glue->open_device(list[i]);
 		err = errno;
 		break;
 	}
 	if (attr_ctx == NULL) {
-		ibv_free_device_list(list);
+		mlx4_glue->free_device_list(list);
 		switch (err) {
 		case 0:
 			rte_errno = ENODEV;
@@ -487,7 +488,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	}
 	ibv_dev = list[i];
 	DEBUG("device opened");
-	if (ibv_query_device(attr_ctx, &device_attr)) {
+	if (mlx4_glue->query_device(attr_ctx, &device_attr)) {
 		rte_errno = ENODEV;
 		goto error;
 	}
@@ -502,7 +503,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	if (!conf.ports.enabled)
 		conf.ports.enabled = conf.ports.present;
 	/* Retrieve extended device attributes. */
-	if (ibv_query_device_ex(attr_ctx, NULL, &device_attr_ex)) {
+	if (mlx4_glue->query_device_ex(attr_ctx, NULL, &device_attr_ex)) {
 		rte_errno = ENODEV;
 		goto error;
 	}
@@ -520,13 +521,13 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		if (!(conf.ports.enabled & (1 << i)))
 			continue;
 		DEBUG("using port %u", port);
-		ctx = ibv_open_device(ibv_dev);
+		ctx = mlx4_glue->open_device(ibv_dev);
 		if (ctx == NULL) {
 			rte_errno = ENODEV;
 			goto port_error;
 		}
 		/* Check port status. */
-		err = ibv_query_port(ctx, port, &port_attr);
+		err = mlx4_glue->query_port(ctx, port, &port_attr);
 		if (err) {
 			rte_errno = err;
 			ERROR("port query failed: %s", strerror(rte_errno));
@@ -540,7 +541,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		}
 		if (port_attr.state != IBV_PORT_ACTIVE)
 			DEBUG("port %d is not active: \"%s\" (%d)",
-			      port, ibv_port_state_str(port_attr.state),
+			      port, mlx4_glue->port_state_str(port_attr.state),
 			      port_attr.state);
 		/* Make asynchronous FD non-blocking to handle interrupts. */
 		if (mlx4_fd_set_non_blocking(ctx->async_fd) < 0) {
@@ -549,7 +550,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			goto port_error;
 		}
 		/* Allocate protection domain. */
-		pd = ibv_alloc_pd(ctx);
+		pd = mlx4_glue->alloc_pd(ctx);
 		if (pd == NULL) {
 			rte_errno = ENOMEM;
 			ERROR("PD allocation failure");
@@ -628,7 +629,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			char name[RTE_ETH_NAME_MAX_LEN];
 
 			snprintf(name, sizeof(name), "%s port %u",
-				 ibv_get_device_name(ibv_dev), port);
+				 mlx4_glue->get_device_name(ibv_dev), port);
 			eth_dev = rte_eth_dev_allocate(name);
 		}
 		if (eth_dev == NULL) {
@@ -671,9 +672,9 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 port_error:
 		rte_free(priv);
 		if (pd)
-			claim_zero(ibv_dealloc_pd(pd));
+			claim_zero(mlx4_glue->dealloc_pd(pd));
 		if (ctx)
-			claim_zero(ibv_close_device(ctx));
+			claim_zero(mlx4_glue->close_device(ctx));
 		if (eth_dev)
 			rte_eth_dev_release_port(eth_dev);
 		break;
@@ -688,9 +689,9 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	 */
 error:
 	if (attr_ctx)
-		claim_zero(ibv_close_device(attr_ctx));
+		claim_zero(mlx4_glue->close_device(attr_ctx));
 	if (list)
-		ibv_free_device_list(list);
+		mlx4_glue->free_device_list(list);
 	assert(rte_errno >= 0);
 	return -rte_errno;
 }
@@ -743,7 +744,7 @@ rte_mlx4_pmd_init(void)
 	 * using this PMD, which is not supported in forked processes.
 	 */
 	setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
-	ibv_fork_init();
+	mlx4_glue->fork_init();
 	rte_pci_register(&mlx4_driver);
 }
 
diff --git a/drivers/net/mlx4/mlx4_ethdev.c b/drivers/net/mlx4/mlx4_ethdev.c
index ca5fadc72..d1d940dc7 100644
--- a/drivers/net/mlx4/mlx4_ethdev.c
+++ b/drivers/net/mlx4/mlx4_ethdev.c
@@ -70,6 +70,7 @@
 
 #include "mlx4.h"
 #include "mlx4_flow.h"
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -1068,7 +1069,7 @@ mlx4_is_removed(struct rte_eth_dev *dev)
 	struct ibv_device_attr device_attr;
 	struct priv *priv = dev->data->dev_private;
 
-	if (ibv_query_device(priv->ctx, &device_attr) == EIO)
+	if (mlx4_glue->query_device(priv->ctx, &device_attr) == EIO)
 		return 1;
 	return 0;
 }
diff --git a/drivers/net/mlx4/mlx4_flow.c b/drivers/net/mlx4/mlx4_flow.c
index 2c6710505..8b6f8a01d 100644
--- a/drivers/net/mlx4/mlx4_flow.c
+++ b/drivers/net/mlx4/mlx4_flow.c
@@ -65,6 +65,7 @@
 
 /* PMD headers. */
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -922,24 +923,25 @@ mlx4_drop_get(struct priv *priv)
 		.priv = priv,
 		.refcnt = 1,
 	};
-	drop->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+	drop->cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 	if (!drop->cq)
 		goto error;
-	drop->qp = ibv_create_qp(priv->pd,
-				 &(struct ibv_qp_init_attr){
-					.send_cq = drop->cq,
-					.recv_cq = drop->cq,
-					.qp_type = IBV_QPT_RAW_PACKET,
-				 });
+	drop->qp = mlx4_glue->create_qp
+		(priv->pd,
+		 &(struct ibv_qp_init_attr){
+			.send_cq = drop->cq,
+			.recv_cq = drop->cq,
+			.qp_type = IBV_QPT_RAW_PACKET,
+		 });
 	if (!drop->qp)
 		goto error;
 	priv->drop = drop;
 	return drop;
 error:
 	if (drop->qp)
-		claim_zero(ibv_destroy_qp(drop->qp));
+		claim_zero(mlx4_glue->destroy_qp(drop->qp));
 	if (drop->cq)
-		claim_zero(ibv_destroy_cq(drop->cq));
+		claim_zero(mlx4_glue->destroy_cq(drop->cq));
 	if (drop)
 		rte_free(drop);
 	rte_errno = ENOMEM;
@@ -959,8 +961,8 @@ mlx4_drop_put(struct mlx4_drop *drop)
 	if (--drop->refcnt)
 		return;
 	drop->priv->drop = NULL;
-	claim_zero(ibv_destroy_qp(drop->qp));
-	claim_zero(ibv_destroy_cq(drop->cq));
+	claim_zero(mlx4_glue->destroy_qp(drop->qp));
+	claim_zero(mlx4_glue->destroy_cq(drop->cq));
 	rte_free(drop);
 }
 
@@ -992,7 +994,7 @@ mlx4_flow_toggle(struct priv *priv,
 	if (!enable) {
 		if (!flow->ibv_flow)
 			return 0;
-		claim_zero(ibv_destroy_flow(flow->ibv_flow));
+		claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 		flow->ibv_flow = NULL;
 		if (flow->drop)
 			mlx4_drop_put(priv->drop);
@@ -1005,7 +1007,7 @@ mlx4_flow_toggle(struct priv *priv,
 	    !priv->isolated &&
 	    flow->ibv_attr->priority == MLX4_FLOW_PRIORITY_LAST) {
 		if (flow->ibv_flow) {
-			claim_zero(ibv_destroy_flow(flow->ibv_flow));
+			claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 			flow->ibv_flow = NULL;
 			if (flow->drop)
 				mlx4_drop_put(priv->drop);
@@ -1035,7 +1037,7 @@ mlx4_flow_toggle(struct priv *priv,
 			if (missing ^ !flow->drop)
 				return 0;
 			/* Verbs flow needs updating. */
-			claim_zero(ibv_destroy_flow(flow->ibv_flow));
+			claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 			flow->ibv_flow = NULL;
 			if (flow->drop)
 				mlx4_drop_put(priv->drop);
@@ -1067,7 +1069,7 @@ mlx4_flow_toggle(struct priv *priv,
 	assert(qp);
 	if (flow->ibv_flow)
 		return 0;
-	flow->ibv_flow = ibv_create_flow(qp, flow->ibv_attr);
+	flow->ibv_flow = mlx4_glue->create_flow(qp, flow->ibv_attr);
 	if (flow->ibv_flow)
 		return 0;
 	if (flow->drop)
diff --git a/drivers/net/mlx4/mlx4_glue.c b/drivers/net/mlx4/mlx4_glue.c
new file mode 100644
index 000000000..30797bd2b
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_glue.c
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox
+ */
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx4dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#include "mlx4_glue.h"
+
+static int
+mlx4_glue_fork_init(void)
+{
+	return ibv_fork_init();
+}
+
+static int
+mlx4_glue_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
+{
+	return ibv_get_async_event(context, event);
+}
+
+static void
+mlx4_glue_ack_async_event(struct ibv_async_event *event)
+{
+	ibv_ack_async_event(event);
+}
+
+static struct ibv_pd *
+mlx4_glue_alloc_pd(struct ibv_context *context)
+{
+	return ibv_alloc_pd(context);
+}
+
+static int
+mlx4_glue_dealloc_pd(struct ibv_pd *pd)
+{
+	return ibv_dealloc_pd(pd);
+}
+
+static struct ibv_device **
+mlx4_glue_get_device_list(int *num_devices)
+{
+	return ibv_get_device_list(num_devices);
+}
+
+static void
+mlx4_glue_free_device_list(struct ibv_device **list)
+{
+	ibv_free_device_list(list);
+}
+
+static struct ibv_context *
+mlx4_glue_open_device(struct ibv_device *device)
+{
+	return ibv_open_device(device);
+}
+
+static int
+mlx4_glue_close_device(struct ibv_context *context)
+{
+	return ibv_close_device(context);
+}
+
+static const char *
+mlx4_glue_get_device_name(struct ibv_device *device)
+{
+	return ibv_get_device_name(device);
+}
+
+static int
+mlx4_glue_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context, device_attr);
+}
+
+static int
+mlx4_glue_query_device_ex(struct ibv_context *context,
+			  const struct ibv_query_device_ex_input *input,
+			  struct ibv_device_attr_ex *attr)
+{
+	return ibv_query_device_ex(context, input, attr);
+}
+
+static int
+mlx4_glue_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context, port_num, port_attr);
+}
+
+static const char *
+mlx4_glue_port_state_str(enum ibv_port_state port_state)
+{
+	return ibv_port_state_str(port_state);
+}
+
+static struct ibv_comp_channel *
+mlx4_glue_create_comp_channel(struct ibv_context *context)
+{
+	return ibv_create_comp_channel(context);
+}
+
+static int
+mlx4_glue_destroy_comp_channel(struct ibv_comp_channel *channel)
+{
+	return ibv_destroy_comp_channel(channel);
+}
+
+static struct ibv_cq *
+mlx4_glue_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+		    struct ibv_comp_channel *channel, int comp_vector)
+{
+	return ibv_create_cq(context, cqe, cq_context, channel, comp_vector);
+}
+
+static int
+mlx4_glue_destroy_cq(struct ibv_cq *cq)
+{
+	return ibv_destroy_cq(cq);
+}
+
+static int
+mlx4_glue_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
+		       void **cq_context)
+{
+	return ibv_get_cq_event(channel, cq, cq_context);
+}
+
+static void
+mlx4_glue_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq, nevents);
+}
+
+static struct ibv_flow *
+mlx4_glue_create_flow(struct ibv_qp *qp, struct ibv_flow_attr *flow)
+{
+	return ibv_create_flow(qp, flow);
+}
+
+static int
+mlx4_glue_destroy_flow(struct ibv_flow *flow_id)
+{
+	return ibv_destroy_flow(flow_id);
+}
+
+static struct ibv_qp *
+mlx4_glue_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
+{
+	return ibv_create_qp(pd, qp_init_attr);
+}
+
+static struct ibv_qp *
+mlx4_glue_create_qp_ex(struct ibv_context *context,
+		       struct ibv_qp_init_attr_ex *qp_init_attr_ex)
+{
+	return ibv_create_qp_ex(context, qp_init_attr_ex);
+}
+
+static int
+mlx4_glue_destroy_qp(struct ibv_qp *qp)
+{
+	return ibv_destroy_qp(qp);
+}
+
+static int
+mlx4_glue_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
+{
+	return ibv_modify_qp(qp, attr, attr_mask);
+}
+
+static struct ibv_mr *
+mlx4_glue_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access)
+{
+	return ibv_reg_mr(pd, addr, length, access);
+}
+
+static int
+mlx4_glue_dereg_mr(struct ibv_mr *mr)
+{
+	return ibv_dereg_mr(mr);
+}
+
+static struct ibv_rwq_ind_table *
+mlx4_glue_create_rwq_ind_table(struct ibv_context *context,
+			       struct ibv_rwq_ind_table_init_attr *init_attr)
+{
+	return ibv_create_rwq_ind_table(context, init_attr);
+}
+
+static int
+mlx4_glue_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table)
+{
+	return ibv_destroy_rwq_ind_table(rwq_ind_table);
+}
+
+static struct ibv_wq *
+mlx4_glue_create_wq(struct ibv_context *context,
+		    struct ibv_wq_init_attr *wq_init_attr)
+{
+	return ibv_create_wq(context, wq_init_attr);
+}
+
+static int
+mlx4_glue_destroy_wq(struct ibv_wq *wq)
+{
+	return ibv_destroy_wq(wq);
+}
+static int
+mlx4_glue_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr)
+{
+	return ibv_modify_wq(wq, wq_attr);
+}
+
+static int
+mlx4_glue_dv_init_obj(struct mlx4dv_obj *obj, uint64_t obj_type)
+{
+	return mlx4dv_init_obj(obj, obj_type);
+}
+
+static int
+mlx4_glue_dv_set_context_attr(struct ibv_context *context,
+			      enum mlx4dv_set_ctx_attr_type attr_type,
+			      void *attr)
+{
+	return mlx4dv_set_context_attr(context, attr_type, attr);
+}
+
+const struct mlx4_glue *mlx4_glue = &(const struct mlx4_glue){
+	.fork_init = mlx4_glue_fork_init,
+	.get_async_event = mlx4_glue_get_async_event,
+	.ack_async_event = mlx4_glue_ack_async_event,
+	.alloc_pd = mlx4_glue_alloc_pd,
+	.dealloc_pd = mlx4_glue_dealloc_pd,
+	.get_device_list = mlx4_glue_get_device_list,
+	.free_device_list = mlx4_glue_free_device_list,
+	.open_device = mlx4_glue_open_device,
+	.close_device = mlx4_glue_close_device,
+	.get_device_name = mlx4_glue_get_device_name,
+	.query_device = mlx4_glue_query_device,
+	.query_device_ex = mlx4_glue_query_device_ex,
+	.query_port = mlx4_glue_query_port,
+	.port_state_str = mlx4_glue_port_state_str,
+	.create_comp_channel = mlx4_glue_create_comp_channel,
+	.destroy_comp_channel = mlx4_glue_destroy_comp_channel,
+	.create_cq = mlx4_glue_create_cq,
+	.destroy_cq = mlx4_glue_destroy_cq,
+	.get_cq_event = mlx4_glue_get_cq_event,
+	.ack_cq_events = mlx4_glue_ack_cq_events,
+	.create_flow = mlx4_glue_create_flow,
+	.destroy_flow = mlx4_glue_destroy_flow,
+	.create_qp = mlx4_glue_create_qp,
+	.create_qp_ex = mlx4_glue_create_qp_ex,
+	.destroy_qp = mlx4_glue_destroy_qp,
+	.modify_qp = mlx4_glue_modify_qp,
+	.reg_mr = mlx4_glue_reg_mr,
+	.dereg_mr = mlx4_glue_dereg_mr,
+	.create_rwq_ind_table = mlx4_glue_create_rwq_ind_table,
+	.destroy_rwq_ind_table = mlx4_glue_destroy_rwq_ind_table,
+	.create_wq = mlx4_glue_create_wq,
+	.destroy_wq = mlx4_glue_destroy_wq,
+	.modify_wq = mlx4_glue_modify_wq,
+	.dv_init_obj = mlx4_glue_dv_init_obj,
+	.dv_set_context_attr = mlx4_glue_dv_set_context_attr,
+};
diff --git a/drivers/net/mlx4/mlx4_glue.h b/drivers/net/mlx4/mlx4_glue.h
new file mode 100644
index 000000000..0623511f2
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_glue.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox
+ */
+
+#ifndef MLX4_GLUE_H_
+#define MLX4_GLUE_H_
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx4dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+struct mlx4_glue {
+	int (*fork_init)(void);
+	int (*get_async_event)(struct ibv_context *context,
+			       struct ibv_async_event *event);
+	void (*ack_async_event)(struct ibv_async_event *event);
+	struct ibv_pd *(*alloc_pd)(struct ibv_context *context);
+	int (*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_device **(*get_device_list)(int *num_devices);
+	void (*free_device_list)(struct ibv_device **list);
+	struct ibv_context *(*open_device)(struct ibv_device *device);
+	int (*close_device)(struct ibv_context *context);
+	const char *(*get_device_name)(struct ibv_device *device);
+	int (*query_device)(struct ibv_context *context,
+			    struct ibv_device_attr *device_attr);
+	int (*query_device_ex)(struct ibv_context *context,
+			       const struct ibv_query_device_ex_input *input,
+			       struct ibv_device_attr_ex *attr);
+	int (*query_port)(struct ibv_context *context, uint8_t port_num,
+			  struct ibv_port_attr *port_attr);
+	const char *(*port_state_str)(enum ibv_port_state port_state);
+	struct ibv_comp_channel *(*create_comp_channel)
+		(struct ibv_context *context);
+	int (*destroy_comp_channel)(struct ibv_comp_channel *channel);
+	struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe,
+				    void *cq_context,
+				    struct ibv_comp_channel *channel,
+				    int comp_vector);
+	int (*destroy_cq)(struct ibv_cq *cq);
+	int (*get_cq_event)(struct ibv_comp_channel *channel,
+			    struct ibv_cq **cq, void **cq_context);
+	void (*ack_cq_events)(struct ibv_cq *cq, unsigned int nevents);
+	struct ibv_flow *(*create_flow)(struct ibv_qp *qp,
+					struct ibv_flow_attr *flow);
+	int (*destroy_flow)(struct ibv_flow *flow_id);
+	struct ibv_qp *(*create_qp)(struct ibv_pd *pd,
+				    struct ibv_qp_init_attr *qp_init_attr);
+	struct ibv_qp *(*create_qp_ex)
+		(struct ibv_context *context,
+		 struct ibv_qp_init_attr_ex *qp_init_attr_ex);
+	int (*destroy_qp)(struct ibv_qp *qp);
+	int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+			 int attr_mask);
+	struct ibv_mr *(*reg_mr)(struct ibv_pd *pd, void *addr,
+				 size_t length, int access);
+	int (*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_rwq_ind_table *(*create_rwq_ind_table)
+		(struct ibv_context *context,
+		 struct ibv_rwq_ind_table_init_attr *init_attr);
+	int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table);
+	struct ibv_wq *(*create_wq)(struct ibv_context *context,
+				    struct ibv_wq_init_attr *wq_init_attr);
+	int (*destroy_wq)(struct ibv_wq *wq);
+	int (*modify_wq)(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr);
+	int (*dv_init_obj)(struct mlx4dv_obj *obj, uint64_t obj_type);
+	int (*dv_set_context_attr)(struct ibv_context *context,
+				   enum mlx4dv_set_ctx_attr_type attr_type,
+				   void *attr);
+};
+
+const struct mlx4_glue *mlx4_glue;
+
+#endif /* MLX4_GLUE_H_ */
diff --git a/drivers/net/mlx4/mlx4_intr.c b/drivers/net/mlx4/mlx4_intr.c
index 2ff72188a..d5ab170f9 100644
--- a/drivers/net/mlx4/mlx4_intr.c
+++ b/drivers/net/mlx4/mlx4_intr.c
@@ -57,6 +57,7 @@
 #include <rte_interrupts.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -216,7 +217,7 @@ mlx4_interrupt_handler(struct priv *priv)
 	unsigned int i;
 
 	/* Read all message and acknowledge them. */
-	while (!ibv_get_async_event(priv->ctx, &event)) {
+	while (!mlx4_glue->get_async_event(priv->ctx, &event)) {
 		switch (event.event_type) {
 		case IBV_EVENT_PORT_ACTIVE:
 		case IBV_EVENT_PORT_ERR:
@@ -231,7 +232,7 @@ mlx4_interrupt_handler(struct priv *priv)
 			DEBUG("event type %d on physical port %d not handled",
 			      event.event_type, event.element.port_num);
 		}
-		ibv_ack_async_event(&event);
+		mlx4_glue->ack_async_event(&event);
 	}
 	for (i = 0; i != RTE_DIM(caught); ++i)
 		if (caught[i])
@@ -354,7 +355,8 @@ mlx4_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
 	if (!rxq || !rxq->channel) {
 		ret = EINVAL;
 	} else {
-		ret = ibv_get_cq_event(rxq->cq->channel, &ev_cq, &ev_ctx);
+		ret = mlx4_glue->get_cq_event(rxq->cq->channel, &ev_cq,
+					      &ev_ctx);
 		if (ret || ev_cq != rxq->cq)
 			ret = EINVAL;
 	}
@@ -364,7 +366,7 @@ mlx4_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
 		     idx);
 	} else {
 		rxq->mcq.arm_sn++;
-		ibv_ack_cq_events(rxq->cq, 1);
+		mlx4_glue->ack_cq_events(rxq->cq, 1);
 	}
 	return -ret;
 }
diff --git a/drivers/net/mlx4/mlx4_mr.c b/drivers/net/mlx4/mlx4_mr.c
index 2a3e2695b..493c00867 100644
--- a/drivers/net/mlx4/mlx4_mr.c
+++ b/drivers/net/mlx4/mlx4_mr.c
@@ -60,6 +60,7 @@
 #include <rte_mempool.h>
 #include <rte_spinlock.h>
 
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -200,8 +201,8 @@ mlx4_mr_get(struct priv *priv, struct rte_mempool *mp)
 		.end = end,
 		.refcnt = 1,
 		.priv = priv,
-		.mr = ibv_reg_mr(priv->pd, (void *)start, end - start,
-				 IBV_ACCESS_LOCAL_WRITE),
+		.mr = mlx4_glue->reg_mr(priv->pd, (void *)start, end - start,
+					IBV_ACCESS_LOCAL_WRITE),
 		.mp = mp,
 	};
 	if (mr->mr) {
@@ -240,7 +241,7 @@ mlx4_mr_put(struct mlx4_mr *mr)
 	if (--mr->refcnt)
 		goto release;
 	LIST_REMOVE(mr, next);
-	claim_zero(ibv_dereg_mr(mr->mr));
+	claim_zero(mlx4_glue->dereg_mr(mr->mr));
 	rte_free(mr);
 release:
 	rte_spinlock_unlock(&priv->mr_lock);
diff --git a/drivers/net/mlx4/mlx4_rxq.c b/drivers/net/mlx4/mlx4_rxq.c
index 163598765..bf60d2fc8 100644
--- a/drivers/net/mlx4/mlx4_rxq.c
+++ b/drivers/net/mlx4/mlx4_rxq.c
@@ -62,6 +62,7 @@
 #include <rte_mempool.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -231,7 +232,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		}
 		ind_tbl[i] = rxq->wq;
 	}
-	rss->ind = ibv_create_rwq_ind_table
+	rss->ind = mlx4_glue->create_rwq_ind_table
 		(priv->ctx,
 		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = rte_log2_u32(RTE_DIM(ind_tbl)),
@@ -243,7 +244,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "RSS indirection table creation failure";
 		goto error;
 	}
-	rss->qp = ibv_create_qp_ex
+	rss->qp = mlx4_glue->create_qp_ex
 		(priv->ctx,
 		 &(struct ibv_qp_init_attr_ex){
 			.comp_mask = (IBV_QP_INIT_ATTR_PD |
@@ -264,7 +265,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "RSS hash QP creation failure";
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(rss->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_INIT,
@@ -275,7 +276,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "failed to switch RSS hash QP to INIT state";
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(rss->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTR,
@@ -288,11 +289,11 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 	return 0;
 error:
 	if (rss->qp) {
-		claim_zero(ibv_destroy_qp(rss->qp));
+		claim_zero(mlx4_glue->destroy_qp(rss->qp));
 		rss->qp = NULL;
 	}
 	if (rss->ind) {
-		claim_zero(ibv_destroy_rwq_ind_table(rss->ind));
+		claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind));
 		rss->ind = NULL;
 	}
 	while (i--)
@@ -325,9 +326,9 @@ mlx4_rss_detach(struct mlx4_rss *rss)
 	assert(rss->ind);
 	if (--rss->usecnt)
 		return;
-	claim_zero(ibv_destroy_qp(rss->qp));
+	claim_zero(mlx4_glue->destroy_qp(rss->qp));
 	rss->qp = NULL;
-	claim_zero(ibv_destroy_rwq_ind_table(rss->ind));
+	claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind));
 	rss->ind = NULL;
 	for (i = 0; i != rss->queues; ++i)
 		mlx4_rxq_detach(priv->dev->data->rx_queues[rss->queue_id[i]]);
@@ -364,9 +365,10 @@ mlx4_rss_init(struct priv *priv)
 	int ret;
 
 	/* Prepare range for RSS contexts before creating the first WQ. */
-	ret = mlx4dv_set_context_attr(priv->ctx,
-				      MLX4DV_SET_CTX_ATTR_LOG_WQS_RANGE_SZ,
-				      &log2_range);
+	ret = mlx4_glue->dv_set_context_attr
+		(priv->ctx,
+		 MLX4DV_SET_CTX_ATTR_LOG_WQS_RANGE_SZ,
+		 &log2_range);
 	if (ret) {
 		ERROR("cannot set up range size for RSS context to %u"
 		      " (for %u Rx queues), error: %s",
@@ -402,13 +404,13 @@ mlx4_rss_init(struct priv *priv)
 		 * sequentially and are guaranteed to never be reused in the
 		 * same context by the underlying implementation.
 		 */
-		cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+		cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 		if (!cq) {
 			ret = ENOMEM;
 			msg = "placeholder CQ creation failure";
 			goto error;
 		}
-		wq = ibv_create_wq
+		wq = mlx4_glue->create_wq
 			(priv->ctx,
 			 &(struct ibv_wq_init_attr){
 				.wq_type = IBV_WQT_RQ,
@@ -419,11 +421,11 @@ mlx4_rss_init(struct priv *priv)
 			 });
 		if (wq) {
 			wq_num = wq->wq_num;
-			claim_zero(ibv_destroy_wq(wq));
+			claim_zero(mlx4_glue->destroy_wq(wq));
 		} else {
 			wq_num = 0; /* Shut up GCC 4.8 warnings. */
 		}
-		claim_zero(ibv_destroy_cq(cq));
+		claim_zero(mlx4_glue->destroy_cq(cq));
 		if (!wq) {
 			ret = ENOMEM;
 			msg = "placeholder WQ creation failure";
@@ -522,13 +524,14 @@ mlx4_rxq_attach(struct rxq *rxq)
 	int ret;
 
 	assert(rte_is_power_of_2(elts_n));
-	cq = ibv_create_cq(priv->ctx, elts_n / sges_n, NULL, rxq->channel, 0);
+	cq = mlx4_glue->create_cq(priv->ctx, elts_n / sges_n, NULL,
+				  rxq->channel, 0);
 	if (!cq) {
 		ret = ENOMEM;
 		msg = "CQ creation failure";
 		goto error;
 	}
-	wq = ibv_create_wq
+	wq = mlx4_glue->create_wq
 		(priv->ctx,
 		 &(struct ibv_wq_init_attr){
 			.wq_type = IBV_WQT_RQ,
@@ -542,7 +545,7 @@ mlx4_rxq_attach(struct rxq *rxq)
 		msg = "WQ creation failure";
 		goto error;
 	}
-	ret = ibv_modify_wq
+	ret = mlx4_glue->modify_wq
 		(wq,
 		 &(struct ibv_wq_attr){
 			.attr_mask = IBV_WQ_ATTR_STATE,
@@ -557,7 +560,7 @@ mlx4_rxq_attach(struct rxq *rxq)
 	mlxdv.cq.out = &dv_cq;
 	mlxdv.rwq.in = wq;
 	mlxdv.rwq.out = &dv_rwq;
-	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_RWQ | MLX4DV_OBJ_CQ);
+	ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_RWQ | MLX4DV_OBJ_CQ);
 	if (ret) {
 		msg = "failed to obtain device information from WQ/CQ objects";
 		goto error;
@@ -619,9 +622,9 @@ mlx4_rxq_attach(struct rxq *rxq)
 	return 0;
 error:
 	if (wq)
-		claim_zero(ibv_destroy_wq(wq));
+		claim_zero(mlx4_glue->destroy_wq(wq));
 	if (cq)
-		claim_zero(ibv_destroy_cq(cq));
+		claim_zero(mlx4_glue->destroy_cq(cq));
 	rte_errno = ret;
 	ERROR("error while attaching Rx queue %p: %s: %s",
 	      (void *)rxq, msg, strerror(ret));
@@ -649,9 +652,9 @@ mlx4_rxq_detach(struct rxq *rxq)
 	memset(&rxq->mcq, 0, sizeof(rxq->mcq));
 	rxq->rq_db = NULL;
 	rxq->wqes = NULL;
-	claim_zero(ibv_destroy_wq(rxq->wq));
+	claim_zero(mlx4_glue->destroy_wq(rxq->wq));
 	rxq->wq = NULL;
-	claim_zero(ibv_destroy_cq(rxq->cq));
+	claim_zero(mlx4_glue->destroy_cq(rxq->cq));
 	rxq->cq = NULL;
 	DEBUG("%p: freeing Rx queue elements", (void *)rxq);
 	for (i = 0; (i != RTE_DIM(*elts)); ++i) {
@@ -879,7 +882,7 @@ mlx4_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		goto error;
 	}
 	if (dev->data->dev_conf.intr_conf.rxq) {
-		rxq->channel = ibv_create_comp_channel(priv->ctx);
+		rxq->channel = mlx4_glue->create_comp_channel(priv->ctx);
 		if (rxq->channel == NULL) {
 			rte_errno = ENOMEM;
 			ERROR("%p: Rx interrupt completion channel creation"
@@ -934,7 +937,7 @@ mlx4_rx_queue_release(void *dpdk_rxq)
 	assert(!rxq->wqes);
 	assert(!rxq->rq_db);
 	if (rxq->channel)
-		claim_zero(ibv_destroy_comp_channel(rxq->channel));
+		claim_zero(mlx4_glue->destroy_comp_channel(rxq->channel));
 	if (rxq->mr)
 		mlx4_mr_put(rxq->mr);
 	rte_free(rxq);
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 2bd4b9cb6..5e4d701cd 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -60,6 +60,7 @@
 #include <rte_mempool.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_prm.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -350,7 +351,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		.lb = !!priv->vf,
 		.bounce_buf = bounce_buf,
 	};
-	txq->cq = ibv_create_cq(priv->ctx, desc, NULL, NULL, 0);
+	txq->cq = mlx4_glue->create_cq(priv->ctx, desc, NULL, NULL, 0);
 	if (!txq->cq) {
 		rte_errno = ENOMEM;
 		ERROR("%p: CQ creation failure: %s",
@@ -370,7 +371,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		/* No completion events must occur by default. */
 		.sq_sig_all = 0,
 	};
-	txq->qp = ibv_create_qp(priv->pd, &qp_init_attr);
+	txq->qp = mlx4_glue->create_qp(priv->pd, &qp_init_attr);
 	if (!txq->qp) {
 		rte_errno = errno ? errno : EINVAL;
 		ERROR("%p: QP creation failure: %s",
@@ -378,7 +379,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		goto error;
 	}
 	txq->max_inline = qp_init_attr.cap.max_inline_data;
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_INIT,
@@ -391,7 +392,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTR,
@@ -403,7 +404,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTS,
@@ -420,7 +421,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 	mlxdv.cq.out = &dv_cq;
 	mlxdv.qp.in = txq->qp;
 	mlxdv.qp.out = &dv_qp;
-	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
+	ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
 	if (ret) {
 		rte_errno = EINVAL;
 		ERROR("%p: failed to obtain information needed for"
@@ -470,9 +471,9 @@ mlx4_tx_queue_release(void *dpdk_txq)
 		}
 	mlx4_txq_free_elts(txq);
 	if (txq->qp)
-		claim_zero(ibv_destroy_qp(txq->qp));
+		claim_zero(mlx4_glue->destroy_qp(txq->qp));
 	if (txq->cq)
-		claim_zero(ibv_destroy_cq(txq->cq));
+		claim_zero(mlx4_glue->destroy_cq(txq->cq));
 	for (i = 0; i != RTE_DIM(txq->mp2mr); ++i) {
 		if (!txq->mp2mr[i].mp)
 			break;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-29 17:19   ` [PATCH v3 " Adrien Mazarguil
  2018-01-29 17:19     ` [PATCH v3 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
@ 2018-01-29 17:19     ` Adrien Mazarguil
  2018-01-29 17:19     ` [PATCH v3 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-29 17:19 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

When mlx4 is not compiled directly as an independent shared object (e.g.
CONFIG_RTE_BUILD_SHARED_LIB not enabled for performance reasons), DPDK
applications inherit its dependencies on libibverbs and libmlx4 through
rte.app.mk.

This is an issue both when DPDK is delivered as a binary package (Linux
distributions) and for end users because rdma-core then propagates as a
mandatory dependency for everything.

Application writers relying on binary DPDK packages are not necessarily
aware of this fact and may end up delivering packages with broken
dependencies.

This patch therefore introduces an intermediate internal plug-in
hard-linked with rdma-core (to preserve symbol versioning) loaded by the
PMD through dlopen(), so that a missing rdma-core does not cause unresolved
symbols, allowing applications to start normally.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 config/common_base        |  1 +
 doc/guides/nics/mlx4.rst  | 13 +++++++++++
 drivers/net/mlx4/Makefile | 29 +++++++++++++++++++++++++
 drivers/net/mlx4/mlx4.c   | 49 ++++++++++++++++++++++++++++++++++++++++++
 mk/rte.app.mk             |  4 ++++
 5 files changed, 96 insertions(+)

diff --git a/config/common_base b/config/common_base
index 170a38939..6df20be0e 100644
--- a/config/common_base
+++ b/config/common_base
@@ -298,6 +298,7 @@ CONFIG_RTE_LIBRTE_AVF_16BYTE_RX_DESC=n
 #
 CONFIG_RTE_LIBRTE_MLX4_PMD=n
 CONFIG_RTE_LIBRTE_MLX4_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS=n
 CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8
 
 #
diff --git a/doc/guides/nics/mlx4.rst b/doc/guides/nics/mlx4.rst
index cab45dfe8..88161781c 100644
--- a/doc/guides/nics/mlx4.rst
+++ b/doc/guides/nics/mlx4.rst
@@ -86,6 +86,19 @@ These options can be modified in the ``.config`` file.
 
   Toggle compilation of librte_pmd_mlx4 itself.
 
+- ``CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS`` (default **n**)
+
+  Build PMD with additional code to make it loadable without hard
+  dependencies on **libibverbs** nor **libmlx4**, which may not be installed
+  on the target system.
+
+  In this mode, their presence is still required for it to run properly,
+  however their absence won't prevent a DPDK application from starting (with
+  ``CONFIG_RTE_BUILD_SHARED_LIB`` disabled) and they won't show up as
+  missing with ``ldd(1)``.
+
+  This option has no performance impact.
+
 - ``CONFIG_RTE_LIBRTE_MLX4_DEBUG`` (default **n**)
 
   Toggle debugging code and stricter compilation flags. Enabling this option
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1d33c38ed..c004ac71c 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -33,12 +33,15 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 # Library name.
 LIB = librte_pmd_mlx4.a
+LIB_GLUE = librte_pmd_mlx4_glue.so
 
 # Sources.
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_flow.c
+ifneq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue.c
+endif
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_intr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxq.c
@@ -46,6 +49,10 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_txq.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_utils.c
 
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+INSTALL-$(CONFIG_RTE_LIBRTE_MLX4_PMD)-lib += $(LIB_GLUE)
+endif
+
 # Basic CFLAGS.
 CFLAGS += -O3
 CFLAGS += -std=c11 -Wall -Wextra
@@ -55,7 +62,13 @@ CFLAGS += -D_BSD_SOURCE
 CFLAGS += -D_DEFAULT_SOURCE
 CFLAGS += -D_XOPEN_SOURCE=600
 CFLAGS += $(WERROR_FLAGS)
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+CFLAGS += -DMLX4_GLUE='"$(LIB_GLUE)"'
+CFLAGS_mlx4_glue.o += -fPIC
+LDLIBS += -ldl
+else
 LDLIBS += -libverbs -lmlx4
+endif
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
@@ -109,7 +122,23 @@ mlx4_autoconf.h: mlx4_autoconf.h.new
 
 $(SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD):.c=.o): mlx4_autoconf.h
 
+# Generate dependency plug-in for rdma-core when the PMD must not be linked
+# directly, so that applications do not inherit this dependency.
+
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+
+$(LIB): $(LIB_GLUE)
+
+$(LIB_GLUE): mlx4_glue.o
+	$Q $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) \
+		-s -shared -o $@ $< -libverbs -lmlx4
+
+mlx4_glue.o: mlx4_autoconf.h
+
+endif
+
 clean_mlx4: FORCE
 	$Q rm -f -- mlx4_autoconf.h mlx4_autoconf.h.new
+	$Q rm -f -- mlx4_glue.o $(LIB_GLUE)
 
 clean: clean_mlx4
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index f304359bb..12e6b431c 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -37,6 +37,7 @@
  */
 
 #include <assert.h>
+#include <dlfcn.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <stddef.h>
@@ -44,6 +45,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 /* Verbs headers do not support -pedantic. */
 #ifdef PEDANTIC
@@ -55,6 +57,7 @@
 #endif
 
 #include <rte_common.h>
+#include <rte_config.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
 #include <rte_ethdev_driver.h>
@@ -724,6 +727,47 @@ static struct rte_pci_driver mlx4_driver = {
 		     RTE_PCI_DRV_INTR_RMV,
 };
 
+#ifdef RTE_LIBRTE_MLX4_DLOPEN_DEPS
+
+/**
+ * Initialization routine for run-time dependency on rdma-core.
+ */
+static int
+mlx4_glue_init(void)
+{
+	void *handle = NULL;
+	void **sym;
+	const char *dlmsg;
+
+	handle = dlopen(MLX4_GLUE, RTLD_LAZY);
+	if (!handle) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot load glue library: %s", dlmsg);
+		goto glue_error;
+	}
+	sym = dlsym(handle, "mlx4_glue");
+	if (!sym || !*sym) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot resolve glue symbol: %s", dlmsg);
+		goto glue_error;
+	}
+	mlx4_glue = *sym;
+	return 0;
+glue_error:
+	if (handle)
+		dlclose(handle);
+	ERROR("cannot initialize PMD due to missing run-time"
+	      " dependency on rdma-core libraries (libibverbs,"
+	      " libmlx4)");
+	return -rte_errno;
+}
+
+#endif
+
 /**
  * Driver initialization routine.
  */
@@ -744,6 +788,11 @@ rte_mlx4_pmd_init(void)
 	 * using this PMD, which is not supported in forked processes.
 	 */
 	setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
+#ifdef RTE_LIBRTE_MLX4_DLOPEN_DEPS
+	if (mlx4_glue_init())
+		return;
+	assert(mlx4_glue);
+#endif
 	mlx4_glue->fork_init();
 	rte_pci_register(&mlx4_driver);
 }
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 0169f3f5b..fdbe36630 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -143,7 +143,11 @@ ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KNI)        += -lrte_pmd_kni
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -ldl
+else
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs -lmlx4
+endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs -lmlx5
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 3/4] net/mlx5: move rdma-core calls to separate file
  2018-01-29 17:19   ` [PATCH v3 " Adrien Mazarguil
  2018-01-29 17:19     ` [PATCH v3 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
  2018-01-29 17:19     ` [PATCH v3 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-29 17:19     ` Adrien Mazarguil
  2018-01-29 17:19     ` [PATCH v3 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
  2018-01-30 15:34     ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  4 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-29 17:19 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

From: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>

This lays the groundwork for externalizing rdma-core as an optional
run-time dependency instead of a mandatory one.

No functional change.

Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 drivers/net/mlx5/Makefile      |   1 +
 drivers/net/mlx5/mlx5.c        |  44 ++---
 drivers/net/mlx5/mlx5_ethdev.c |   7 +-
 drivers/net/mlx5/mlx5_flow.c   |  92 +++++------
 drivers/net/mlx5/mlx5_glue.c   | 321 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h   |  99 +++++++++++
 drivers/net/mlx5/mlx5_mr.c     |   7 +-
 drivers/net/mlx5/mlx5_rxq.c    |  54 +++---
 drivers/net/mlx5/mlx5_txq.c    |  22 +--
 drivers/net/mlx5/mlx5_vlan.c   |  13 +-
 10 files changed, 548 insertions(+), 112 deletions(-)

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index a3984eb9f..bdec30692 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -53,6 +53,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
 
 # Basic CFLAGS.
 CFLAGS += -O3
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 5a959f7c5..b911d0ad4 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -65,6 +65,7 @@
 #include "mlx5_rxtx.h"
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
+#include "mlx5_glue.h"
 
 /* Device parameter to enable RX completion queue compression. */
 #define MLX5_RXQ_CQE_COMP_EN "rxq_cqe_comp_en"
@@ -218,8 +219,8 @@ mlx5_dev_close(struct rte_eth_dev *dev)
 	}
 	if (priv->pd != NULL) {
 		assert(priv->ctx != NULL);
-		claim_zero(ibv_dealloc_pd(priv->pd));
-		claim_zero(ibv_close_device(priv->ctx));
+		claim_zero(mlx5_glue->dealloc_pd(priv->pd));
+		claim_zero(mlx5_glue->close_device(priv->ctx));
 	} else
 		assert(priv->ctx == NULL);
 	if (priv->rss_conf.rss_key != NULL)
@@ -625,7 +626,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 	/* Save PCI address. */
 	mlx5_dev[idx].pci_addr = pci_dev->addr;
-	list = ibv_get_device_list(&i);
+	list = mlx5_glue->get_device_list(&i);
 	if (list == NULL) {
 		assert(errno);
 		if (errno == ENOSYS)
@@ -675,12 +676,12 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		     " (SR-IOV: %s)",
 		     list[i]->name,
 		     sriov ? "true" : "false");
-		attr_ctx = ibv_open_device(list[i]);
+		attr_ctx = mlx5_glue->open_device(list[i]);
 		err = errno;
 		break;
 	}
 	if (attr_ctx == NULL) {
-		ibv_free_device_list(list);
+		mlx5_glue->free_device_list(list);
 		switch (err) {
 		case 0:
 			ERROR("cannot access device, is mlx5_ib loaded?");
@@ -699,7 +700,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	 * Multi-packet send is supported by ConnectX-4 Lx PF as well
 	 * as all ConnectX-5 devices.
 	 */
-	mlx5dv_query_device(attr_ctx, &attrs_out);
+	mlx5_glue->dv_query_device(attr_ctx, &attrs_out);
 	if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_MPW_ALLOWED) {
 		if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_ENHANCED_MPW) {
 			DEBUG("Enhanced MPW is supported");
@@ -717,7 +718,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		cqe_comp = 0;
 	else
 		cqe_comp = 1;
-	if (ibv_query_device_ex(attr_ctx, NULL, &device_attr))
+	if (mlx5_glue->query_device_ex(attr_ctx, NULL, &device_attr))
 		goto error;
 	INFO("%u port(s) detected", device_attr.orig_attr.phys_port_cnt);
 
@@ -794,15 +795,15 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 		DEBUG("using port %u (%08" PRIx32 ")", port, test);
 
-		ctx = ibv_open_device(ibv_dev);
+		ctx = mlx5_glue->open_device(ibv_dev);
 		if (ctx == NULL) {
 			err = ENODEV;
 			goto port_error;
 		}
 
-		ibv_query_device_ex(ctx, NULL, &device_attr);
+		mlx5_glue->query_device_ex(ctx, NULL, &device_attr);
 		/* Check port status. */
-		err = ibv_query_port(ctx, port, &port_attr);
+		err = mlx5_glue->query_port(ctx, port, &port_attr);
 		if (err) {
 			ERROR("port query failed: %s", strerror(err));
 			goto port_error;
@@ -817,11 +818,11 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 		if (port_attr.state != IBV_PORT_ACTIVE)
 			DEBUG("port %d is not active: \"%s\" (%d)",
-			      port, ibv_port_state_str(port_attr.state),
+			      port, mlx5_glue->port_state_str(port_attr.state),
 			      port_attr.state);
 
 		/* Allocate protection domain. */
-		pd = ibv_alloc_pd(ctx);
+		pd = mlx5_glue->alloc_pd(ctx);
 		if (pd == NULL) {
 			ERROR("PD allocation failure");
 			err = ENOMEM;
@@ -853,7 +854,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			      strerror(err));
 			goto port_error;
 		}
-		if (ibv_query_device_ex(ctx, NULL, &device_attr_ex)) {
+		if (mlx5_glue->query_device_ex(ctx, NULL, &device_attr_ex)) {
 			ERROR("ibv_query_device_ex() failed");
 			goto port_error;
 		}
@@ -873,7 +874,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
 		config.flow_counter_en = !!(device_attr.max_counter_sets);
-		ibv_describe_counter_set(ctx, 0, &cs_desc);
+		mlx5_glue->describe_counter_set(ctx, 0, &cs_desc);
 		DEBUG("counter type = %d, num of cs = %ld, attributes = %d",
 		      cs_desc.counter_type, cs_desc.num_of_cs,
 		      cs_desc.attributes);
@@ -984,8 +985,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			.free = &mlx5_free_verbs_buf,
 			.data = priv,
 		};
-		mlx5dv_set_context_attr(ctx, MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
-					(void *)((uintptr_t)&alctr));
+		mlx5_glue->dv_set_context_attr(ctx,
+					       MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
+					       (void *)((uintptr_t)&alctr));
 
 		/* Bring Ethernet device up. */
 		DEBUG("forcing Ethernet interface up");
@@ -998,9 +1000,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		if (priv)
 			rte_free(priv);
 		if (pd)
-			claim_zero(ibv_dealloc_pd(pd));
+			claim_zero(mlx5_glue->dealloc_pd(pd));
 		if (ctx)
-			claim_zero(ibv_close_device(ctx));
+			claim_zero(mlx5_glue->close_device(ctx));
 		break;
 	}
 
@@ -1019,9 +1021,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 error:
 	if (attr_ctx)
-		claim_zero(ibv_close_device(attr_ctx));
+		claim_zero(mlx5_glue->close_device(attr_ctx));
 	if (list)
-		ibv_free_device_list(list);
+		mlx5_glue->free_device_list(list);
 	assert(err >= 0);
 	return -err;
 }
@@ -1092,7 +1094,7 @@ rte_mlx5_pmd_init(void)
 	/* Match the size of Rx completion entry to the size of a cacheline. */
 	if (RTE_CACHE_LINE_SIZE == 128)
 		setenv("MLX5_CQE_SIZE", "128", 0);
-	ibv_fork_init();
+	mlx5_glue->fork_init();
 	rte_pci_register(&mlx5_driver);
 }
 
diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c
index 83657f509..cbc735a8b 100644
--- a/drivers/net/mlx5/mlx5_ethdev.c
+++ b/drivers/net/mlx5/mlx5_ethdev.c
@@ -64,6 +64,7 @@
 #include <rte_malloc.h>
 
 #include "mlx5.h"
+#include "mlx5_glue.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_utils.h"
 
@@ -1261,7 +1262,7 @@ priv_dev_status_handler(struct priv *priv)
 
 	/* Read all message and acknowledge them. */
 	for (;;) {
-		if (ibv_get_async_event(priv->ctx, &event))
+		if (mlx5_glue->get_async_event(priv->ctx, &event))
 			break;
 		if ((event.event_type == IBV_EVENT_PORT_ACTIVE ||
 			event.event_type == IBV_EVENT_PORT_ERR) &&
@@ -1273,7 +1274,7 @@ priv_dev_status_handler(struct priv *priv)
 		else
 			DEBUG("event type %d on port %d not handled",
 			      event.event_type, event.element.port_num);
-		ibv_ack_async_event(&event);
+		mlx5_glue->ack_async_event(&event);
 	}
 	if (ret & (1 << RTE_ETH_EVENT_INTR_LSC))
 		if (priv_link_status_update(priv))
@@ -1559,7 +1560,7 @@ mlx5_is_removed(struct rte_eth_dev *dev)
 	struct ibv_device_attr device_attr;
 	struct priv *priv = dev->data->dev_private;
 
-	if (ibv_query_device(priv->ctx, &device_attr) == EIO)
+	if (mlx5_glue->query_device(priv->ctx, &device_attr) == EIO)
 		return 1;
 	return 0;
 }
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index bf8eff8a5..800ec9f07 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -53,6 +53,7 @@
 #include "mlx5.h"
 #include "mlx5_defs.h"
 #include "mlx5_prm.h"
+#include "mlx5_glue.h"
 
 /* Define minimal priority for control plane flows. */
 #define MLX5_CTRL_FLOW_PRIORITY 4
@@ -62,22 +63,9 @@
 #define MLX5_IPV6 6
 
 #ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
-struct ibv_counter_set_init_attr {
-	int dummy;
-};
 struct ibv_flow_spec_counter_action {
 	int dummy;
 };
-struct ibv_counter_set {
-	int dummy;
-};
-
-static inline int
-ibv_destroy_counter_set(struct ibv_counter_set *cs)
-{
-	(void)cs;
-	return -ENOTSUP;
-}
 #endif
 
 /* Dev ops structure defined in mlx5.c */
@@ -1649,7 +1637,7 @@ mlx5_flow_create_count(struct priv *priv __rte_unused,
 	};
 
 	init_attr.counter_set_id = 0;
-	parser->cs = ibv_create_counter_set(priv->ctx, &init_attr);
+	parser->cs = mlx5_glue->create_counter_set(priv->ctx, &init_attr);
 	if (!parser->cs)
 		return EINVAL;
 	counter.counter_set_handle = parser->cs->handle;
@@ -1702,8 +1690,8 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 		return 0;
 	parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
 	flow->frxq[HASH_RXQ_ETH].ibv_flow =
-		ibv_create_flow(priv->flow_drop_queue->qp,
-				flow->frxq[HASH_RXQ_ETH].ibv_attr);
+		mlx5_glue->create_flow(priv->flow_drop_queue->qp,
+				       flow->frxq[HASH_RXQ_ETH].ibv_attr);
 	if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
 		rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
 				   NULL, "flow rule creation failure");
@@ -1714,7 +1702,8 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 error:
 	assert(flow);
 	if (flow->frxq[HASH_RXQ_ETH].ibv_flow) {
-		claim_zero(ibv_destroy_flow(flow->frxq[HASH_RXQ_ETH].ibv_flow));
+		claim_zero(mlx5_glue->destroy_flow
+			   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 		flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
 	}
 	if (flow->frxq[HASH_RXQ_ETH].ibv_attr) {
@@ -1722,7 +1711,7 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 		flow->frxq[HASH_RXQ_ETH].ibv_attr = NULL;
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 		parser->cs = NULL;
 	}
@@ -1826,8 +1815,8 @@ priv_flow_create_action_queue(struct priv *priv,
 		if (!flow->frxq[i].hrxq)
 			continue;
 		flow->frxq[i].ibv_flow =
-			ibv_create_flow(flow->frxq[i].hrxq->qp,
-					flow->frxq[i].ibv_attr);
+			mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
+					       flow->frxq[i].ibv_attr);
 		if (!flow->frxq[i].ibv_flow) {
 			rte_flow_error_set(error, ENOMEM,
 					   RTE_FLOW_ERROR_TYPE_HANDLE,
@@ -1853,7 +1842,7 @@ priv_flow_create_action_queue(struct priv *priv,
 		if (flow->frxq[i].ibv_flow) {
 			struct ibv_flow *ibv_flow = flow->frxq[i].ibv_flow;
 
-			claim_zero(ibv_destroy_flow(ibv_flow));
+			claim_zero(mlx5_glue->destroy_flow(ibv_flow));
 		}
 		if (flow->frxq[i].hrxq)
 			mlx5_priv_hrxq_release(priv, flow->frxq[i].hrxq);
@@ -1861,7 +1850,7 @@ priv_flow_create_action_queue(struct priv *priv,
 			rte_free(flow->frxq[i].ibv_attr);
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 		parser->cs = NULL;
 	}
@@ -2039,7 +2028,7 @@ priv_flow_destroy(struct priv *priv,
 free:
 	if (flow->drop) {
 		if (flow->frxq[HASH_RXQ_ETH].ibv_flow)
-			claim_zero(ibv_destroy_flow
+			claim_zero(mlx5_glue->destroy_flow
 				   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 		rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
 	} else {
@@ -2047,7 +2036,8 @@ priv_flow_destroy(struct priv *priv,
 			struct mlx5_flow *frxq = &flow->frxq[i];
 
 			if (frxq->ibv_flow)
-				claim_zero(ibv_destroy_flow(frxq->ibv_flow));
+				claim_zero(mlx5_glue->destroy_flow
+					   (frxq->ibv_flow));
 			if (frxq->hrxq)
 				mlx5_priv_hrxq_release(priv, frxq->hrxq);
 			if (frxq->ibv_attr)
@@ -2055,7 +2045,7 @@ priv_flow_destroy(struct priv *priv,
 		}
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 	}
 	TAILQ_REMOVE(list, flow, next);
@@ -2103,35 +2093,38 @@ priv_flow_create_drop_queue(struct priv *priv)
 		WARN("cannot allocate memory for drop queue");
 		goto error;
 	}
-	fdq->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+	fdq->cq = mlx5_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 	if (!fdq->cq) {
 		WARN("cannot allocate CQ for drop queue");
 		goto error;
 	}
-	fdq->wq = ibv_create_wq(priv->ctx,
-			&(struct ibv_wq_init_attr){
+	fdq->wq = mlx5_glue->create_wq
+		(priv->ctx,
+		 &(struct ibv_wq_init_attr){
 			.wq_type = IBV_WQT_RQ,
 			.max_wr = 1,
 			.max_sge = 1,
 			.pd = priv->pd,
 			.cq = fdq->cq,
-			});
+		 });
 	if (!fdq->wq) {
 		WARN("cannot allocate WQ for drop queue");
 		goto error;
 	}
-	fdq->ind_table = ibv_create_rwq_ind_table(priv->ctx,
-			&(struct ibv_rwq_ind_table_init_attr){
+	fdq->ind_table = mlx5_glue->create_rwq_ind_table
+		(priv->ctx,
+		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = 0,
 			.ind_tbl = &fdq->wq,
 			.comp_mask = 0,
-			});
+		 });
 	if (!fdq->ind_table) {
 		WARN("cannot allocate indirection table for drop queue");
 		goto error;
 	}
-	fdq->qp = ibv_create_qp_ex(priv->ctx,
-		&(struct ibv_qp_init_attr_ex){
+	fdq->qp = mlx5_glue->create_qp_ex
+		(priv->ctx,
+		 &(struct ibv_qp_init_attr_ex){
 			.qp_type = IBV_QPT_RAW_PACKET,
 			.comp_mask =
 				IBV_QP_INIT_ATTR_PD |
@@ -2146,7 +2139,7 @@ priv_flow_create_drop_queue(struct priv *priv)
 				},
 			.rwq_ind_tbl = fdq->ind_table,
 			.pd = priv->pd
-		});
+		 });
 	if (!fdq->qp) {
 		WARN("cannot allocate QP for drop queue");
 		goto error;
@@ -2155,13 +2148,13 @@ priv_flow_create_drop_queue(struct priv *priv)
 	return 0;
 error:
 	if (fdq->qp)
-		claim_zero(ibv_destroy_qp(fdq->qp));
+		claim_zero(mlx5_glue->destroy_qp(fdq->qp));
 	if (fdq->ind_table)
-		claim_zero(ibv_destroy_rwq_ind_table(fdq->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
 	if (fdq->wq)
-		claim_zero(ibv_destroy_wq(fdq->wq));
+		claim_zero(mlx5_glue->destroy_wq(fdq->wq));
 	if (fdq->cq)
-		claim_zero(ibv_destroy_cq(fdq->cq));
+		claim_zero(mlx5_glue->destroy_cq(fdq->cq));
 	if (fdq)
 		rte_free(fdq);
 	priv->flow_drop_queue = NULL;
@@ -2182,13 +2175,13 @@ priv_flow_delete_drop_queue(struct priv *priv)
 	if (!fdq)
 		return;
 	if (fdq->qp)
-		claim_zero(ibv_destroy_qp(fdq->qp));
+		claim_zero(mlx5_glue->destroy_qp(fdq->qp));
 	if (fdq->ind_table)
-		claim_zero(ibv_destroy_rwq_ind_table(fdq->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
 	if (fdq->wq)
-		claim_zero(ibv_destroy_wq(fdq->wq));
+		claim_zero(mlx5_glue->destroy_wq(fdq->wq));
 	if (fdq->cq)
-		claim_zero(ibv_destroy_cq(fdq->cq));
+		claim_zero(mlx5_glue->destroy_cq(fdq->cq));
 	rte_free(fdq);
 	priv->flow_drop_queue = NULL;
 }
@@ -2212,7 +2205,7 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
 		if (flow->drop) {
 			if (!flow->frxq[HASH_RXQ_ETH].ibv_flow)
 				continue;
-			claim_zero(ibv_destroy_flow
+			claim_zero(mlx5_glue->destroy_flow
 				   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 			flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
 			/* Next flow. */
@@ -2233,7 +2226,8 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
 		for (i = 0; i != hash_rxq_init_n; ++i) {
 			if (!flow->frxq[i].ibv_flow)
 				continue;
-			claim_zero(ibv_destroy_flow(flow->frxq[i].ibv_flow));
+			claim_zero(mlx5_glue->destroy_flow
+				   (flow->frxq[i].ibv_flow));
 			flow->frxq[i].ibv_flow = NULL;
 			mlx5_priv_hrxq_release(priv, flow->frxq[i].hrxq);
 			flow->frxq[i].hrxq = NULL;
@@ -2263,7 +2257,7 @@ priv_flow_start(struct priv *priv, struct mlx5_flows *list)
 
 		if (flow->drop) {
 			flow->frxq[HASH_RXQ_ETH].ibv_flow =
-				ibv_create_flow
+				mlx5_glue->create_flow
 				(priv->flow_drop_queue->qp,
 				 flow->frxq[HASH_RXQ_ETH].ibv_attr);
 			if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
@@ -2301,8 +2295,8 @@ priv_flow_start(struct priv *priv, struct mlx5_flows *list)
 			}
 flow_create:
 			flow->frxq[i].ibv_flow =
-				ibv_create_flow(flow->frxq[i].hrxq->qp,
-						flow->frxq[i].ibv_attr);
+				mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
+						       flow->frxq[i].ibv_attr);
 			if (!flow->frxq[i].ibv_flow) {
 				DEBUG("Flow %p cannot be applied",
 				      (void *)flow);
@@ -2509,7 +2503,7 @@ priv_flow_query_count(struct ibv_counter_set *cs,
 		.out = counters,
 		.outlen = 2 * sizeof(uint64_t),
 	};
-	int res = ibv_query_counter_set(&query_cs_attr, &query_out);
+	int res = mlx5_glue->query_counter_set(&query_cs_attr, &query_out);
 
 	if (res) {
 		rte_flow_error_set(error, -res,
diff --git a/drivers/net/mlx5/mlx5_glue.c b/drivers/net/mlx5/mlx5_glue.c
new file mode 100644
index 000000000..2ae5a5345
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_glue.c
@@ -0,0 +1,321 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox Technologies, Ltd.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
+
+static int
+mlx5_glue_fork_init(void)
+{
+	return ibv_fork_init();
+}
+
+static struct ibv_pd *
+mlx5_glue_alloc_pd(struct ibv_context *context)
+{
+	return ibv_alloc_pd(context);
+}
+
+static int
+mlx5_glue_dealloc_pd(struct ibv_pd *pd)
+{
+	return ibv_dealloc_pd(pd);
+}
+
+static struct ibv_device **
+mlx5_glue_get_device_list(int *num_devices)
+{
+	return ibv_get_device_list(num_devices);
+}
+
+static void
+mlx5_glue_free_device_list(struct ibv_device **list)
+{
+	ibv_free_device_list(list);
+}
+
+static struct ibv_context *
+mlx5_glue_open_device(struct ibv_device *device)
+{
+	return ibv_open_device(device);
+}
+
+static int
+mlx5_glue_close_device(struct ibv_context *context)
+{
+	return ibv_close_device(context);
+}
+
+static int
+mlx5_glue_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context, device_attr);
+}
+
+static int
+mlx5_glue_query_device_ex(struct ibv_context *context,
+			  const struct ibv_query_device_ex_input *input,
+			  struct ibv_device_attr_ex *attr)
+{
+	return ibv_query_device_ex(context, input, attr);
+}
+
+static int
+mlx5_glue_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context, port_num, port_attr);
+}
+
+static struct ibv_comp_channel *
+mlx5_glue_create_comp_channel(struct ibv_context *context)
+{
+	return ibv_create_comp_channel(context);
+}
+
+static int
+mlx5_glue_destroy_comp_channel(struct ibv_comp_channel *channel)
+{
+	return ibv_destroy_comp_channel(channel);
+}
+
+static struct ibv_cq *
+mlx5_glue_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+		    struct ibv_comp_channel *channel, int comp_vector)
+{
+	return ibv_create_cq(context, cqe, cq_context, channel, comp_vector);
+}
+
+static int
+mlx5_glue_destroy_cq(struct ibv_cq *cq)
+{
+	return ibv_destroy_cq(cq);
+}
+
+static int
+mlx5_glue_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
+		       void **cq_context)
+{
+	return ibv_get_cq_event(channel, cq, cq_context);
+}
+
+static void
+mlx5_glue_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq, nevents);
+}
+
+static struct ibv_rwq_ind_table *
+mlx5_glue_create_rwq_ind_table(struct ibv_context *context,
+			       struct ibv_rwq_ind_table_init_attr *init_attr)
+{
+	return ibv_create_rwq_ind_table(context, init_attr);
+}
+
+static int
+mlx5_glue_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table)
+{
+	return ibv_destroy_rwq_ind_table(rwq_ind_table);
+}
+
+static struct ibv_wq *
+mlx5_glue_create_wq(struct ibv_context *context,
+		    struct ibv_wq_init_attr *wq_init_attr)
+{
+	return ibv_create_wq(context, wq_init_attr);
+}
+
+static int
+mlx5_glue_destroy_wq(struct ibv_wq *wq)
+{
+	return ibv_destroy_wq(wq);
+}
+static int
+mlx5_glue_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr)
+{
+	return ibv_modify_wq(wq, wq_attr);
+}
+
+static struct ibv_flow *
+mlx5_glue_create_flow(struct ibv_qp *qp, struct ibv_flow_attr *flow)
+{
+	return ibv_create_flow(qp, flow);
+}
+
+static int
+mlx5_glue_destroy_flow(struct ibv_flow *flow_id)
+{
+	return ibv_destroy_flow(flow_id);
+}
+
+static struct ibv_qp *
+mlx5_glue_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
+{
+	return ibv_create_qp(pd, qp_init_attr);
+}
+
+static struct ibv_qp *
+mlx5_glue_create_qp_ex(struct ibv_context *context,
+		       struct ibv_qp_init_attr_ex *qp_init_attr_ex)
+{
+	return ibv_create_qp_ex(context, qp_init_attr_ex);
+}
+
+static int
+mlx5_glue_destroy_qp(struct ibv_qp *qp)
+{
+	return ibv_destroy_qp(qp);
+}
+
+static int
+mlx5_glue_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
+{
+	return ibv_modify_qp(qp, attr, attr_mask);
+}
+
+static struct ibv_mr *
+mlx5_glue_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access)
+{
+	return ibv_reg_mr(pd, addr, length, access);
+}
+
+static int
+mlx5_glue_dereg_mr(struct ibv_mr *mr)
+{
+	return ibv_dereg_mr(mr);
+}
+
+static struct ibv_counter_set *
+mlx5_glue_create_counter_set(struct ibv_context *context,
+			     struct ibv_counter_set_init_attr *init_attr)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)context;
+	(void)init_attr;
+	return NULL;
+#else
+	return ibv_create_counter_set(context, init_attr);
+#endif
+}
+
+static inline int
+mlx5_glue_destroy_counter_set(struct ibv_counter_set *cs)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)cs;
+	return -ENOTSUP;
+#else
+	return ibv_destroy_counter_set(cs);
+#endif
+}
+
+static void
+mlx5_glue_ack_async_event(struct ibv_async_event *event)
+{
+	ibv_ack_async_event(event);
+}
+
+static int
+mlx5_glue_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
+{
+	return ibv_get_async_event(context, event);
+}
+
+static const char *
+mlx5_glue_port_state_str(enum ibv_port_state port_state)
+{
+	return ibv_port_state_str(port_state);
+}
+
+static struct ibv_cq *
+mlx5_glue_cq_ex_to_cq(struct ibv_cq_ex *cq)
+{
+	return ibv_cq_ex_to_cq(cq);
+}
+
+static struct ibv_cq_ex *
+mlx5_glue_dv_create_cq(struct ibv_context *context,
+		       struct ibv_cq_init_attr_ex *cq_attr,
+		       struct mlx5dv_cq_init_attr *mlx5_cq_attr)
+{
+	return mlx5dv_create_cq(context, cq_attr, mlx5_cq_attr);
+}
+
+static int
+mlx5_glue_dv_query_device(struct ibv_context *ctx,
+			  struct mlx5dv_context *attrs_out)
+{
+	return mlx5dv_query_device(ctx, attrs_out);
+}
+
+static int
+mlx5_glue_dv_set_context_attr(struct ibv_context *ibv_ctx,
+			      enum mlx5dv_set_ctx_attr_type type, void *attr)
+{
+	return mlx5dv_set_context_attr(ibv_ctx, type, attr);
+}
+
+static int
+mlx5_glue_dv_init_obj(struct mlx5dv_obj *obj, uint64_t obj_type)
+{
+	return mlx5dv_init_obj(obj, obj_type);
+}
+
+const struct mlx5_glue *mlx5_glue = &(const struct mlx5_glue){
+	.fork_init = mlx5_glue_fork_init,
+	.alloc_pd = mlx5_glue_alloc_pd,
+	.dealloc_pd = mlx5_glue_dealloc_pd,
+	.get_device_list = mlx5_glue_get_device_list,
+	.free_device_list = mlx5_glue_free_device_list,
+	.open_device = mlx5_glue_open_device,
+	.close_device = mlx5_glue_close_device,
+	.query_device = mlx5_glue_query_device,
+	.query_device_ex = mlx5_glue_query_device_ex,
+	.query_port = mlx5_glue_query_port,
+	.create_comp_channel = mlx5_glue_create_comp_channel,
+	.destroy_comp_channel = mlx5_glue_destroy_comp_channel,
+	.create_cq = mlx5_glue_create_cq,
+	.destroy_cq = mlx5_glue_destroy_cq,
+	.get_cq_event = mlx5_glue_get_cq_event,
+	.ack_cq_events = mlx5_glue_ack_cq_events,
+	.create_rwq_ind_table = mlx5_glue_create_rwq_ind_table,
+	.destroy_rwq_ind_table = mlx5_glue_destroy_rwq_ind_table,
+	.create_wq = mlx5_glue_create_wq,
+	.destroy_wq = mlx5_glue_destroy_wq,
+	.modify_wq = mlx5_glue_modify_wq,
+	.create_flow = mlx5_glue_create_flow,
+	.destroy_flow = mlx5_glue_destroy_flow,
+	.create_qp = mlx5_glue_create_qp,
+	.create_qp_ex = mlx5_glue_create_qp_ex,
+	.destroy_qp = mlx5_glue_destroy_qp,
+	.modify_qp = mlx5_glue_modify_qp,
+	.reg_mr = mlx5_glue_reg_mr,
+	.dereg_mr = mlx5_glue_dereg_mr,
+	.create_counter_set = mlx5_glue_create_counter_set,
+	.destroy_counter_set = mlx5_glue_destroy_counter_set,
+	.ack_async_event = mlx5_glue_ack_async_event,
+	.get_async_event = mlx5_glue_get_async_event,
+	.port_state_str = mlx5_glue_port_state_str,
+	.cq_ex_to_cq = mlx5_glue_cq_ex_to_cq,
+	.dv_create_cq = mlx5_glue_dv_create_cq,
+	.dv_query_device = mlx5_glue_dv_query_device,
+	.dv_set_context_attr = mlx5_glue_dv_set_context_attr,
+	.dv_init_obj = mlx5_glue_dv_init_obj,
+};
diff --git a/drivers/net/mlx5/mlx5_glue.h b/drivers/net/mlx5/mlx5_glue.h
new file mode 100644
index 000000000..dc69b2895
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_glue.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox Technologies, Ltd.
+ */
+
+#ifndef MLX5_GLUE_H_
+#define MLX5_GLUE_H_
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+struct ibv_counter_set_init_attr {
+	int dummy;
+};
+struct ibv_counter_set {
+	int dummy;
+};
+#endif
+
+struct mlx5_glue {
+	int (*fork_init)(void);
+	struct ibv_pd *(*alloc_pd)(struct ibv_context *context);
+	int (*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_device **(*get_device_list)(int *num_devices);
+	void (*free_device_list)(struct ibv_device **list);
+	struct ibv_context *(*open_device)(struct ibv_device *device);
+	int (*close_device)(struct ibv_context *context);
+	int (*query_device)(struct ibv_context *context,
+			    struct ibv_device_attr *device_attr);
+	int (*query_device_ex)(struct ibv_context *context,
+			       const struct ibv_query_device_ex_input *input,
+			       struct ibv_device_attr_ex *attr);
+	int (*query_port)(struct ibv_context *context, uint8_t port_num,
+			  struct ibv_port_attr *port_attr);
+	struct ibv_comp_channel *(*create_comp_channel)
+		(struct ibv_context *context);
+	int (*destroy_comp_channel)(struct ibv_comp_channel *channel);
+	struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe,
+				    void *cq_context,
+				    struct ibv_comp_channel *channel,
+				    int comp_vector);
+	int (*destroy_cq)(struct ibv_cq *cq);
+	int (*get_cq_event)(struct ibv_comp_channel *channel,
+			    struct ibv_cq **cq, void **cq_context);
+	void (*ack_cq_events)(struct ibv_cq *cq, unsigned int nevents);
+	struct ibv_rwq_ind_table *(*create_rwq_ind_table)
+		(struct ibv_context *context,
+		 struct ibv_rwq_ind_table_init_attr *init_attr);
+	int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table);
+	struct ibv_wq *(*create_wq)(struct ibv_context *context,
+				    struct ibv_wq_init_attr *wq_init_attr);
+	int (*destroy_wq)(struct ibv_wq *wq);
+	int (*modify_wq)(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr);
+	struct ibv_flow *(*create_flow)(struct ibv_qp *qp,
+					struct ibv_flow_attr *flow);
+	int (*destroy_flow)(struct ibv_flow *flow_id);
+	struct ibv_qp *(*create_qp)(struct ibv_pd *pd,
+				    struct ibv_qp_init_attr *qp_init_attr);
+	struct ibv_qp *(*create_qp_ex)
+		(struct ibv_context *context,
+		 struct ibv_qp_init_attr_ex *qp_init_attr_ex);
+	int (*destroy_qp)(struct ibv_qp *qp);
+	int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+			 int attr_mask);
+	struct ibv_mr *(*reg_mr)(struct ibv_pd *pd, void *addr,
+				 size_t length, int access);
+	int (*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_counter_set *(*create_counter_set)
+		(struct ibv_context *context,
+		 struct ibv_counter_set_init_attr *init_attr);
+	int (*destroy_counter_set)(struct ibv_counter_set *cs);
+	void (*ack_async_event)(struct ibv_async_event *event);
+	int (*get_async_event)(struct ibv_context *context,
+			       struct ibv_async_event *event);
+	const char *(*port_state_str)(enum ibv_port_state port_state);
+	struct ibv_cq *(*cq_ex_to_cq)(struct ibv_cq_ex *cq);
+	struct ibv_cq_ex *(*dv_create_cq)
+		(struct ibv_context *context,
+		 struct ibv_cq_init_attr_ex *cq_attr,
+		 struct mlx5dv_cq_init_attr *mlx5_cq_attr);
+	int (*dv_query_device)(struct ibv_context *ctx_in,
+			       struct mlx5dv_context *attrs_out);
+	int (*dv_set_context_attr)(struct ibv_context *ibv_ctx,
+				   enum mlx5dv_set_ctx_attr_type type,
+				   void *attr);
+	int (*dv_init_obj)(struct mlx5dv_obj *obj, uint64_t obj_type);
+};
+
+const struct mlx5_glue *mlx5_glue;
+
+#endif /* MLX5_GLUE_H_ */
diff --git a/drivers/net/mlx5/mlx5_mr.c b/drivers/net/mlx5/mlx5_mr.c
index 33d037d28..28769d386 100644
--- a/drivers/net/mlx5/mlx5_mr.c
+++ b/drivers/net/mlx5/mlx5_mr.c
@@ -46,6 +46,7 @@
 
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
+#include "mlx5_glue.h"
 
 struct mlx5_check_mempool_data {
 	int ret;
@@ -315,8 +316,8 @@ priv_mr_new(struct priv *priv, struct rte_mempool *mp)
 	DEBUG("mempool %p using start=%p end=%p size=%zu for MR",
 	      (void *)mp, (void *)start, (void *)end,
 	      (size_t)(end - start));
-	mr->mr = ibv_reg_mr(priv->pd, (void *)start, end - start,
-			    IBV_ACCESS_LOCAL_WRITE);
+	mr->mr = mlx5_glue->reg_mr(priv->pd, (void *)start, end - start,
+				   IBV_ACCESS_LOCAL_WRITE);
 	mr->mp = mp;
 	mr->lkey = rte_cpu_to_be_32(mr->mr->lkey);
 	rte_atomic32_inc(&mr->refcnt);
@@ -372,7 +373,7 @@ priv_mr_release(struct priv *priv, struct mlx5_mr *mr)
 	DEBUG("Memory Region %p refcnt: %d",
 	      (void *)mr, rte_atomic32_read(&mr->refcnt));
 	if (rte_atomic32_dec_and_test(&mr->refcnt)) {
-		claim_zero(ibv_dereg_mr(mr->mr));
+		claim_zero(mlx5_glue->dereg_mr(mr->mr));
 		LIST_REMOVE(mr, next);
 		rte_free(mr);
 		return 0;
diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c
index 3c716b960..c7b884ab5 100644
--- a/drivers/net/mlx5/mlx5_rxq.c
+++ b/drivers/net/mlx5/mlx5_rxq.c
@@ -63,6 +63,7 @@
 #include "mlx5_utils.h"
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
+#include "mlx5_glue.h"
 
 /* Default RSS hash key also used for ConnectX-3. */
 uint8_t rss_hash_default_key[] = {
@@ -601,13 +602,13 @@ mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id)
 		ret = EINVAL;
 		goto exit;
 	}
-	ret = ibv_get_cq_event(rxq_ibv->channel, &ev_cq, &ev_ctx);
+	ret = mlx5_glue->get_cq_event(rxq_ibv->channel, &ev_cq, &ev_ctx);
 	if (ret || ev_cq != rxq_ibv->cq) {
 		ret = EINVAL;
 		goto exit;
 	}
 	rxq_data->cq_arm_sn++;
-	ibv_ack_cq_events(rxq_ibv->cq, 1);
+	mlx5_glue->ack_cq_events(rxq_ibv->cq, 1);
 exit:
 	if (rxq_ibv)
 		mlx5_priv_rxq_ibv_release(priv, rxq_ibv);
@@ -675,7 +676,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		}
 	}
 	if (rxq_ctrl->irq) {
-		tmpl->channel = ibv_create_comp_channel(priv->ctx);
+		tmpl->channel = mlx5_glue->create_comp_channel(priv->ctx);
 		if (!tmpl->channel) {
 			ERROR("%p: Comp Channel creation failure",
 			      (void *)rxq_ctrl);
@@ -703,8 +704,9 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	} else if (config->cqe_comp && rxq_data->hw_timestamp) {
 		DEBUG("Rx CQE compression is disabled for HW timestamp");
 	}
-	tmpl->cq = ibv_cq_ex_to_cq(mlx5dv_create_cq(priv->ctx, &attr.cq.ibv,
-						    &attr.cq.mlx5));
+	tmpl->cq = mlx5_glue->cq_ex_to_cq
+		(mlx5_glue->dv_create_cq(priv->ctx, &attr.cq.ibv,
+					 &attr.cq.mlx5));
 	if (tmpl->cq == NULL) {
 		ERROR("%p: CQ creation failure", (void *)rxq_ctrl);
 		goto error;
@@ -740,7 +742,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		attr.wq.comp_mask |= IBV_WQ_INIT_ATTR_FLAGS;
 	}
 #endif
-	tmpl->wq = ibv_create_wq(priv->ctx, &attr.wq);
+	tmpl->wq = mlx5_glue->create_wq(priv->ctx, &attr.wq);
 	if (tmpl->wq == NULL) {
 		ERROR("%p: WQ creation failure", (void *)rxq_ctrl);
 		goto error;
@@ -764,7 +766,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		.attr_mask = IBV_WQ_ATTR_STATE,
 		.wq_state = IBV_WQS_RDY,
 	};
-	ret = ibv_modify_wq(tmpl->wq, &mod);
+	ret = mlx5_glue->modify_wq(tmpl->wq, &mod);
 	if (ret) {
 		ERROR("%p: WQ state to IBV_WQS_RDY failed",
 		      (void *)rxq_ctrl);
@@ -774,7 +776,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	obj.cq.out = &cq_info;
 	obj.rwq.in = tmpl->wq;
 	obj.rwq.out = &rwq;
-	ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_RWQ);
+	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_RWQ);
 	if (ret != 0)
 		goto error;
 	if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
@@ -824,11 +826,11 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	return tmpl;
 error:
 	if (tmpl->wq)
-		claim_zero(ibv_destroy_wq(tmpl->wq));
+		claim_zero(mlx5_glue->destroy_wq(tmpl->wq));
 	if (tmpl->cq)
-		claim_zero(ibv_destroy_cq(tmpl->cq));
+		claim_zero(mlx5_glue->destroy_cq(tmpl->cq));
 	if (tmpl->channel)
-		claim_zero(ibv_destroy_comp_channel(tmpl->channel));
+		claim_zero(mlx5_glue->destroy_comp_channel(tmpl->channel));
 	if (tmpl->mr)
 		priv_mr_release(priv, tmpl->mr);
 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
@@ -894,10 +896,11 @@ mlx5_priv_rxq_ibv_release(struct priv *priv, struct mlx5_rxq_ibv *rxq_ibv)
 	      (void *)rxq_ibv, rte_atomic32_read(&rxq_ibv->refcnt));
 	if (rte_atomic32_dec_and_test(&rxq_ibv->refcnt)) {
 		rxq_free_elts(rxq_ibv->rxq_ctrl);
-		claim_zero(ibv_destroy_wq(rxq_ibv->wq));
-		claim_zero(ibv_destroy_cq(rxq_ibv->cq));
+		claim_zero(mlx5_glue->destroy_wq(rxq_ibv->wq));
+		claim_zero(mlx5_glue->destroy_cq(rxq_ibv->cq));
 		if (rxq_ibv->channel)
-			claim_zero(ibv_destroy_comp_channel(rxq_ibv->channel));
+			claim_zero(mlx5_glue->destroy_comp_channel
+				   (rxq_ibv->channel));
 		LIST_REMOVE(rxq_ibv, next);
 		rte_free(rxq_ibv);
 		return 0;
@@ -1225,13 +1228,13 @@ mlx5_priv_ind_table_ibv_new(struct priv *priv, uint16_t queues[],
 	/* Finalise indirection table. */
 	for (j = 0; i != (unsigned int)(1 << wq_n); ++i, ++j)
 		wq[i] = wq[j];
-	ind_tbl->ind_table = ibv_create_rwq_ind_table(
-		priv->ctx,
-		&(struct ibv_rwq_ind_table_init_attr){
+	ind_tbl->ind_table = mlx5_glue->create_rwq_ind_table
+		(priv->ctx,
+		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = wq_n,
 			.ind_tbl = wq,
 			.comp_mask = 0,
-		});
+		 });
 	if (!ind_tbl->ind_table)
 		goto error;
 	rte_atomic32_inc(&ind_tbl->refcnt);
@@ -1303,7 +1306,8 @@ mlx5_priv_ind_table_ibv_release(struct priv *priv,
 	DEBUG("%p: Indirection table %p: refcnt %d", (void *)priv,
 	      (void *)ind_tbl, rte_atomic32_read(&ind_tbl->refcnt));
 	if (rte_atomic32_dec_and_test(&ind_tbl->refcnt))
-		claim_zero(ibv_destroy_rwq_ind_table(ind_tbl->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table
+			   (ind_tbl->ind_table));
 	for (i = 0; i != ind_tbl->queues_n; ++i)
 		claim_nonzero(mlx5_priv_rxq_release(priv, ind_tbl->queues[i]));
 	if (!rte_atomic32_read(&ind_tbl->refcnt)) {
@@ -1370,9 +1374,9 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 		ind_tbl = mlx5_priv_ind_table_ibv_new(priv, queues, queues_n);
 	if (!ind_tbl)
 		return NULL;
-	qp = ibv_create_qp_ex(
-		priv->ctx,
-		&(struct ibv_qp_init_attr_ex){
+	qp = mlx5_glue->create_qp_ex
+		(priv->ctx,
+		 &(struct ibv_qp_init_attr_ex){
 			.qp_type = IBV_QPT_RAW_PACKET,
 			.comp_mask =
 				IBV_QP_INIT_ATTR_PD |
@@ -1386,7 +1390,7 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 			},
 			.rwq_ind_tbl = ind_tbl->ind_table,
 			.pd = priv->pd,
-		});
+		 });
 	if (!qp)
 		goto error;
 	hrxq = rte_calloc(__func__, 1, sizeof(*hrxq) + rss_key_len, 0);
@@ -1405,7 +1409,7 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 error:
 	mlx5_priv_ind_table_ibv_release(priv, ind_tbl);
 	if (qp)
-		claim_zero(ibv_destroy_qp(qp));
+		claim_zero(mlx5_glue->destroy_qp(qp));
 	return NULL;
 }
 
@@ -1473,7 +1477,7 @@ mlx5_priv_hrxq_release(struct priv *priv, struct mlx5_hrxq *hrxq)
 	DEBUG("%p: Hash Rx queue %p: refcnt %d", (void *)priv,
 	      (void *)hrxq, rte_atomic32_read(&hrxq->refcnt));
 	if (rte_atomic32_dec_and_test(&hrxq->refcnt)) {
-		claim_zero(ibv_destroy_qp(hrxq->qp));
+		claim_zero(mlx5_glue->destroy_qp(hrxq->qp));
 		mlx5_priv_ind_table_ibv_release(priv, hrxq->ind_table);
 		LIST_REMOVE(hrxq, next);
 		rte_free(hrxq);
diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c
index 65086d36f..bdaca5a00 100644
--- a/drivers/net/mlx5/mlx5_txq.c
+++ b/drivers/net/mlx5/mlx5_txq.c
@@ -59,6 +59,7 @@
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
 
 /**
  * Allocate TX queue elements.
@@ -432,7 +433,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		((desc / MLX5_TX_COMP_THRESH) - 1) : 1;
 	if (is_empw_burst_func(tx_pkt_burst))
 		cqe_n += MLX5_TX_COMP_THRESH_INLINE_DIV;
-	tmpl.cq = ibv_create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
+	tmpl.cq = mlx5_glue->create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
 	if (tmpl.cq == NULL) {
 		ERROR("%p: CQ creation failure", (void *)txq_ctrl);
 		goto error;
@@ -473,7 +474,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		attr.init.max_tso_header = txq_ctrl->max_tso_header;
 		attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
 	}
-	tmpl.qp = ibv_create_qp_ex(priv->ctx, &attr.init);
+	tmpl.qp = mlx5_glue->create_qp_ex(priv->ctx, &attr.init);
 	if (tmpl.qp == NULL) {
 		ERROR("%p: QP creation failure", (void *)txq_ctrl);
 		goto error;
@@ -484,7 +485,8 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		/* Primary port number. */
 		.port_num = priv->port
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, (IBV_QP_STATE | IBV_QP_PORT));
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod,
+				   (IBV_QP_STATE | IBV_QP_PORT));
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_INIT failed", (void *)txq_ctrl);
 		goto error;
@@ -492,13 +494,13 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	attr.mod = (struct ibv_qp_attr){
 		.qp_state = IBV_QPS_RTR
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_RTR failed", (void *)txq_ctrl);
 		goto error;
 	}
 	attr.mod.qp_state = IBV_QPS_RTS;
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_RTS failed", (void *)txq_ctrl);
 		goto error;
@@ -513,7 +515,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	obj.cq.out = &cq_info;
 	obj.qp.in = tmpl.qp;
 	obj.qp.out = &qp;
-	ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
+	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
 	if (ret != 0)
 		goto error;
 	if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
@@ -553,9 +555,9 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	return txq_ibv;
 error:
 	if (tmpl.cq)
-		claim_zero(ibv_destroy_cq(tmpl.cq));
+		claim_zero(mlx5_glue->destroy_cq(tmpl.cq));
 	if (tmpl.qp)
-		claim_zero(ibv_destroy_qp(tmpl.qp));
+		claim_zero(mlx5_glue->destroy_qp(tmpl.qp));
 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
 	return NULL;
 }
@@ -609,8 +611,8 @@ mlx5_priv_txq_ibv_release(struct priv *priv, struct mlx5_txq_ibv *txq_ibv)
 	DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
 	      (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
 	if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
-		claim_zero(ibv_destroy_qp(txq_ibv->qp));
-		claim_zero(ibv_destroy_cq(txq_ibv->cq));
+		claim_zero(mlx5_glue->destroy_qp(txq_ibv->qp));
+		claim_zero(mlx5_glue->destroy_cq(txq_ibv->cq));
 		LIST_REMOVE(txq_ibv, next);
 		rte_free(txq_ibv);
 		return 0;
diff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c
index d51dbe941..f55e5e020 100644
--- a/drivers/net/mlx5/mlx5_vlan.c
+++ b/drivers/net/mlx5/mlx5_vlan.c
@@ -36,12 +36,23 @@
 #include <assert.h>
 #include <stdint.h>
 
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
 #include <rte_ethdev_driver.h>
 #include <rte_common.h>
 
 #include "mlx5_utils.h"
 #include "mlx5.h"
 #include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
 
 /**
  * DPDK callback to configure a VLAN filter.
@@ -138,7 +149,7 @@ priv_vlan_strip_queue_set(struct priv *priv, uint16_t idx, int on)
 		.flags = vlan_offloads,
 	};
 
-	err = ibv_modify_wq(rxq_ctrl->ibv->wq, &mod);
+	err = mlx5_glue->modify_wq(rxq_ctrl->ibv->wq, &mod);
 	if (err) {
 		ERROR("%p: failed to modified stripping mode: %s",
 		      (void *)priv, strerror(err));
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 4/4] net/mlx5: spawn rdma-core dependency plug-in
  2018-01-29 17:19   ` [PATCH v3 " Adrien Mazarguil
                       ` (2 preceding siblings ...)
  2018-01-29 17:19     ` [PATCH v3 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
@ 2018-01-29 17:19     ` Adrien Mazarguil
  2018-01-30 15:34     ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  4 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-29 17:19 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

When mlx5 is not compiled directly as an independent shared object (e.g.
CONFIG_RTE_BUILD_SHARED_LIB not enabled for performance reasons), DPDK
applications inherit its dependencies on libibverbs and libmlx5 through
rte.app.mk.

This is an issue both when DPDK is delivered as a binary package (Linux
distributions) and for end users because rdma-core then propagates as a
mandatory dependency for everything.

Application writers relying on binary DPDK packages are not necessarily
aware of this fact and may end up delivering packages with broken
dependencies.

This patch therefore introduces an intermediate internal plug-in
hard-linked with rdma-core (to preserve symbol versioning) loaded by the
PMD through dlopen(), so that a missing rdma-core does not cause unresolved
symbols, allowing applications to start normally.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 config/common_base        |  1 +
 doc/guides/nics/mlx5.rst  | 13 ++++++++++++
 drivers/net/mlx5/Makefile | 31 ++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5.c   | 48 ++++++++++++++++++++++++++++++++++++++++++
 mk/rte.app.mk             |  4 ++++
 5 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/config/common_base b/config/common_base
index 6df20be0e..b9b421db7 100644
--- a/config/common_base
+++ b/config/common_base
@@ -306,6 +306,7 @@ CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8
 #
 CONFIG_RTE_LIBRTE_MLX5_PMD=n
 CONFIG_RTE_LIBRTE_MLX5_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=n
 CONFIG_RTE_LIBRTE_MLX5_TX_MP_CACHE=8
 
 #
diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index 2e6d1e45a..a9e4bf51a 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -159,6 +159,19 @@ These options can be modified in the ``.config`` file.
 
   Toggle compilation of librte_pmd_mlx5 itself.
 
+- ``CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS`` (default **n**)
+
+  Build PMD with additional code to make it loadable without hard
+  dependencies on **libibverbs** nor **libmlx5**, which may not be installed
+  on the target system.
+
+  In this mode, their presence is still required for it to run properly,
+  however their absence won't prevent a DPDK application from starting (with
+  ``CONFIG_RTE_BUILD_SHARED_LIB`` disabled) and they won't show up as
+  missing with ``ldd(1)``.
+
+  This option has no performance impact.
+
 - ``CONFIG_RTE_LIBRTE_MLX5_DEBUG`` (default **n**)
 
   Toggle debugging code and stricter compilation flags. Enabling this option
diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index bdec30692..4b20d718b 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -33,9 +33,13 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 # Library name.
 LIB = librte_pmd_mlx5.a
+LIB_GLUE = librte_pmd_mlx5_glue.so
 
 # Sources.
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5.c
+ifneq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
+endif
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rxq.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_txq.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rxtx.c
@@ -53,7 +57,10 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c
-SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
+
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+INSTALL-$(CONFIG_RTE_LIBRTE_MLX5_PMD)-lib += $(LIB_GLUE)
+endif
 
 # Basic CFLAGS.
 CFLAGS += -O3
@@ -65,7 +72,13 @@ CFLAGS += -D_DEFAULT_SOURCE
 CFLAGS += -D_XOPEN_SOURCE=600
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -Wno-strict-prototypes
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+CFLAGS += -DMLX5_GLUE='"$(LIB_GLUE)"'
+CFLAGS_mlx5_glue.o += -fPIC
+LDLIBS += -ldl
+else
 LDLIBS += -libverbs -lmlx5
+endif
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
@@ -158,7 +171,23 @@ mlx5_autoconf.h: mlx5_autoconf.h.new
 
 $(SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD):.c=.o): mlx5_autoconf.h
 
+# Generate dependency plug-in for rdma-core when the PMD must not be linked
+# directly, so that applications do not inherit this dependency.
+
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+
+$(LIB): $(LIB_GLUE)
+
+$(LIB_GLUE): mlx5_glue.o
+	$Q $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) \
+		-s -shared -o $@ $< -libverbs -lmlx5
+
+mlx5_glue.o: mlx5_autoconf.h
+
+endif
+
 clean_mlx5: FORCE
 	$Q rm -f -- mlx5_autoconf.h mlx5_autoconf.h.new
+	$Q rm -f -- mlx5_glue.o $(LIB_GLUE)
 
 clean: clean_mlx5
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index b911d0ad4..466a8b0a2 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -35,6 +35,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>
+#include <dlfcn.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -57,6 +58,7 @@
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
 #include <rte_common.h>
+#include <rte_config.h>
 #include <rte_eal_memconfig.h>
 #include <rte_kvargs.h>
 
@@ -1075,6 +1077,47 @@ static struct rte_pci_driver mlx5_driver = {
 	.drv_flags = RTE_PCI_DRV_INTR_LSC | RTE_PCI_DRV_INTR_RMV,
 };
 
+#ifdef RTE_LIBRTE_MLX5_DLOPEN_DEPS
+
+/**
+ * Initialization routine for run-time dependency on rdma-core.
+ */
+static int
+mlx5_glue_init(void)
+{
+	void *handle = NULL;
+	void **sym;
+	const char *dlmsg;
+
+	handle = dlopen(MLX5_GLUE, RTLD_LAZY);
+	if (!handle) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot load glue library: %s", dlmsg);
+		goto glue_error;
+	}
+	sym = dlsym(handle, "mlx5_glue");
+	if (!sym || !*sym) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot resolve glue symbol: %s", dlmsg);
+		goto glue_error;
+	}
+	mlx5_glue = *sym;
+	return 0;
+glue_error:
+	if (handle)
+		dlclose(handle);
+	ERROR("cannot initialize PMD due to missing run-time"
+	      " dependency on rdma-core libraries (libibverbs,"
+	      " libmlx5)");
+	return -rte_errno;
+}
+
+#endif
+
 /**
  * Driver initialization routine.
  */
@@ -1094,6 +1137,11 @@ rte_mlx5_pmd_init(void)
 	/* Match the size of Rx completion entry to the size of a cacheline. */
 	if (RTE_CACHE_LINE_SIZE == 128)
 		setenv("MLX5_CQE_SIZE", "128", 0);
+#ifdef RTE_LIBRTE_MLX5_DLOPEN_DEPS
+	if (mlx5_glue_init())
+		return;
+	assert(mlx5_glue);
+#endif
 	mlx5_glue->fork_init();
 	rte_pci_register(&mlx5_driver);
 }
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index fdbe36630..88f626049 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -148,7 +148,11 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -ldl
 else
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs -lmlx4
 endif
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -ldl
+else
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs -lmlx5
+endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time
  2018-01-29 17:19   ` [PATCH v3 " Adrien Mazarguil
                       ` (3 preceding siblings ...)
  2018-01-29 17:19     ` [PATCH v3 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-30 15:34     ` Adrien Mazarguil
  2018-01-30 15:34       ` [PATCH v4 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
                         ` (4 more replies)
  4 siblings, 5 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-30 15:34 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

A problem encountered with Mellanox PMDs and frequently reported by DPDK
application developers and Linux distribution package maintainers is their
dependency on rdma-core components, namely libibverbs, libmlx4, and libmlx5.

For best performance in applications, DPDK is normally built as a collection
of library archives (.a files), whose external dependencies are inherited
through rte.app.mk during link.

When these PMDs are built-in, any binary DPDK package, whether DPDK itself
or derived applications, always have to pull rdma-core. This dependency is
not obvious and may be missed during the packaging of any intermediate layer
between DPDK itself and the end application.

While still required during compilation, this series trades this hard
dependency for an optional one, dynamically loaded at run-time through
dlopen().

It supersedes Shachar's previous work on the same topic [1] using a
different approach in order to preserve symbol versioning and address
the remaining issues.

[1] http://dpdk.org/ml/archives/dev/2017-December/085090.html

v4 changes:

- Addressed remaining compilation issue against MLNX_OFED due to missing
  function definitions in mlx5.
- Fixed sign of errno code returned by glue functions when counters are not
  supported.

v3 changes:

- Rebased on dpdk-next-net-mlx.
- Modified patches to generate mlx4/mlx5 glue objects as independent
  libraries to install on the target system (they are not generated at run
  time anymore) in order to address security concerns.
- As a consequence, glue libraries generation is now disabled by default and
  binary distributions must take care of properly packaging them if enabled.

v2 changes:

- Rebased on dpdk-next-net-mlx.
- Rely on CONFIG_RTE_LIBRTE_MLX[45]_DLOPEN_DEPS instead of
  CONFIG_RTE_BUILD_SHARED_LIB to enable this mode, so it can be overridden
  if necessary.
- Fixed -lmlx5 -libibverbs leftovers in rte.app.mk.
- Minor fixes for indentation and unnecessary includes in mlx5.

Adrien Mazarguil (3):
  net/mlx4: move rdma-core calls to separate file
  net/mlx4: spawn rdma-core dependency plug-in
  net/mlx5: spawn rdma-core dependency plug-in

Nelio Laranjeiro (1):
  net/mlx5: move rdma-core calls to separate file

 config/common_base             |   2 +
 doc/guides/nics/mlx4.rst       |  13 ++
 doc/guides/nics/mlx5.rst       |  13 ++
 drivers/net/mlx4/Makefile      |  30 +++
 drivers/net/mlx4/mlx4.c        |  84 +++++++--
 drivers/net/mlx4/mlx4_ethdev.c |   3 +-
 drivers/net/mlx4/mlx4_flow.c   |  32 ++--
 drivers/net/mlx4/mlx4_glue.c   | 275 ++++++++++++++++++++++++++++
 drivers/net/mlx4/mlx4_glue.h   |  80 ++++++++
 drivers/net/mlx4/mlx4_intr.c   |  10 +-
 drivers/net/mlx4/mlx4_mr.c     |   7 +-
 drivers/net/mlx4/mlx4_rxq.c    |  53 +++---
 drivers/net/mlx4/mlx4_txq.c    |  17 +-
 drivers/net/mlx5/Makefile      |  30 +++
 drivers/net/mlx5/mlx5.c        |  92 +++++++---
 drivers/net/mlx5/mlx5_ethdev.c |   7 +-
 drivers/net/mlx5/mlx5_flow.c   |  92 +++++-----
 drivers/net/mlx5/mlx5_glue.c   | 352 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h   | 106 +++++++++++
 drivers/net/mlx5/mlx5_mr.c     |   7 +-
 drivers/net/mlx5/mlx5_rxq.c    |  54 +++---
 drivers/net/mlx5/mlx5_txq.c    |  22 ++-
 drivers/net/mlx5/mlx5_vlan.c   |  13 +-
 mk/rte.app.mk                  |   8 +
 24 files changed, 1217 insertions(+), 185 deletions(-)
 create mode 100644 drivers/net/mlx4/mlx4_glue.c
 create mode 100644 drivers/net/mlx4/mlx4_glue.h
 create mode 100644 drivers/net/mlx5/mlx5_glue.c
 create mode 100644 drivers/net/mlx5/mlx5_glue.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v4 1/4] net/mlx4: move rdma-core calls to separate file
  2018-01-30 15:34     ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
@ 2018-01-30 15:34       ` Adrien Mazarguil
  2018-01-30 15:34       ` [PATCH v4 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
                         ` (3 subsequent siblings)
  4 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-30 15:34 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

This lays the groundwork for externalizing rdma-core as an optional
run-time dependency instead of a mandatory one.

No functional change.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
---
 drivers/net/mlx4/Makefile      |   1 +
 drivers/net/mlx4/mlx4.c        |  35 ++---
 drivers/net/mlx4/mlx4_ethdev.c |   3 +-
 drivers/net/mlx4/mlx4_flow.c   |  32 +++--
 drivers/net/mlx4/mlx4_glue.c   | 275 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx4/mlx4_glue.h   |  80 +++++++++++
 drivers/net/mlx4/mlx4_intr.c   |  10 +-
 drivers/net/mlx4/mlx4_mr.c     |   7 +-
 drivers/net/mlx4/mlx4_rxq.c    |  53 +++----
 drivers/net/mlx4/mlx4_txq.c    |  17 +--
 10 files changed, 440 insertions(+), 73 deletions(-)

diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1f95e0df9..1d33c38ed 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -38,6 +38,7 @@ LIB = librte_pmd_mlx4.a
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_intr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxq.c
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 952dae08a..f304359bb 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -67,6 +67,7 @@
 #include <rte_mbuf.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -218,8 +219,8 @@ mlx4_dev_close(struct rte_eth_dev *dev)
 		mlx4_tx_queue_release(dev->data->tx_queues[i]);
 	if (priv->pd != NULL) {
 		assert(priv->ctx != NULL);
-		claim_zero(ibv_dealloc_pd(priv->pd));
-		claim_zero(ibv_close_device(priv->ctx));
+		claim_zero(mlx4_glue->dealloc_pd(priv->pd));
+		claim_zero(mlx4_glue->close_device(priv->ctx));
 	} else
 		assert(priv->ctx == NULL);
 	mlx4_intr_uninstall(priv);
@@ -436,7 +437,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 	(void)pci_drv;
 	assert(pci_drv == &mlx4_driver);
-	list = ibv_get_device_list(&i);
+	list = mlx4_glue->get_device_list(&i);
 	if (list == NULL) {
 		rte_errno = errno;
 		assert(rte_errno);
@@ -465,12 +466,12 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		      PCI_DEVICE_ID_MELLANOX_CONNECTX3VF);
 		INFO("PCI information matches, using device \"%s\" (VF: %s)",
 		     list[i]->name, (vf ? "true" : "false"));
-		attr_ctx = ibv_open_device(list[i]);
+		attr_ctx = mlx4_glue->open_device(list[i]);
 		err = errno;
 		break;
 	}
 	if (attr_ctx == NULL) {
-		ibv_free_device_list(list);
+		mlx4_glue->free_device_list(list);
 		switch (err) {
 		case 0:
 			rte_errno = ENODEV;
@@ -487,7 +488,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	}
 	ibv_dev = list[i];
 	DEBUG("device opened");
-	if (ibv_query_device(attr_ctx, &device_attr)) {
+	if (mlx4_glue->query_device(attr_ctx, &device_attr)) {
 		rte_errno = ENODEV;
 		goto error;
 	}
@@ -502,7 +503,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	if (!conf.ports.enabled)
 		conf.ports.enabled = conf.ports.present;
 	/* Retrieve extended device attributes. */
-	if (ibv_query_device_ex(attr_ctx, NULL, &device_attr_ex)) {
+	if (mlx4_glue->query_device_ex(attr_ctx, NULL, &device_attr_ex)) {
 		rte_errno = ENODEV;
 		goto error;
 	}
@@ -520,13 +521,13 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		if (!(conf.ports.enabled & (1 << i)))
 			continue;
 		DEBUG("using port %u", port);
-		ctx = ibv_open_device(ibv_dev);
+		ctx = mlx4_glue->open_device(ibv_dev);
 		if (ctx == NULL) {
 			rte_errno = ENODEV;
 			goto port_error;
 		}
 		/* Check port status. */
-		err = ibv_query_port(ctx, port, &port_attr);
+		err = mlx4_glue->query_port(ctx, port, &port_attr);
 		if (err) {
 			rte_errno = err;
 			ERROR("port query failed: %s", strerror(rte_errno));
@@ -540,7 +541,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		}
 		if (port_attr.state != IBV_PORT_ACTIVE)
 			DEBUG("port %d is not active: \"%s\" (%d)",
-			      port, ibv_port_state_str(port_attr.state),
+			      port, mlx4_glue->port_state_str(port_attr.state),
 			      port_attr.state);
 		/* Make asynchronous FD non-blocking to handle interrupts. */
 		if (mlx4_fd_set_non_blocking(ctx->async_fd) < 0) {
@@ -549,7 +550,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			goto port_error;
 		}
 		/* Allocate protection domain. */
-		pd = ibv_alloc_pd(ctx);
+		pd = mlx4_glue->alloc_pd(ctx);
 		if (pd == NULL) {
 			rte_errno = ENOMEM;
 			ERROR("PD allocation failure");
@@ -628,7 +629,7 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			char name[RTE_ETH_NAME_MAX_LEN];
 
 			snprintf(name, sizeof(name), "%s port %u",
-				 ibv_get_device_name(ibv_dev), port);
+				 mlx4_glue->get_device_name(ibv_dev), port);
 			eth_dev = rte_eth_dev_allocate(name);
 		}
 		if (eth_dev == NULL) {
@@ -671,9 +672,9 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 port_error:
 		rte_free(priv);
 		if (pd)
-			claim_zero(ibv_dealloc_pd(pd));
+			claim_zero(mlx4_glue->dealloc_pd(pd));
 		if (ctx)
-			claim_zero(ibv_close_device(ctx));
+			claim_zero(mlx4_glue->close_device(ctx));
 		if (eth_dev)
 			rte_eth_dev_release_port(eth_dev);
 		break;
@@ -688,9 +689,9 @@ mlx4_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	 */
 error:
 	if (attr_ctx)
-		claim_zero(ibv_close_device(attr_ctx));
+		claim_zero(mlx4_glue->close_device(attr_ctx));
 	if (list)
-		ibv_free_device_list(list);
+		mlx4_glue->free_device_list(list);
 	assert(rte_errno >= 0);
 	return -rte_errno;
 }
@@ -743,7 +744,7 @@ rte_mlx4_pmd_init(void)
 	 * using this PMD, which is not supported in forked processes.
 	 */
 	setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
-	ibv_fork_init();
+	mlx4_glue->fork_init();
 	rte_pci_register(&mlx4_driver);
 }
 
diff --git a/drivers/net/mlx4/mlx4_ethdev.c b/drivers/net/mlx4/mlx4_ethdev.c
index ca5fadc72..d1d940dc7 100644
--- a/drivers/net/mlx4/mlx4_ethdev.c
+++ b/drivers/net/mlx4/mlx4_ethdev.c
@@ -70,6 +70,7 @@
 
 #include "mlx4.h"
 #include "mlx4_flow.h"
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -1068,7 +1069,7 @@ mlx4_is_removed(struct rte_eth_dev *dev)
 	struct ibv_device_attr device_attr;
 	struct priv *priv = dev->data->dev_private;
 
-	if (ibv_query_device(priv->ctx, &device_attr) == EIO)
+	if (mlx4_glue->query_device(priv->ctx, &device_attr) == EIO)
 		return 1;
 	return 0;
 }
diff --git a/drivers/net/mlx4/mlx4_flow.c b/drivers/net/mlx4/mlx4_flow.c
index 2c6710505..8b6f8a01d 100644
--- a/drivers/net/mlx4/mlx4_flow.c
+++ b/drivers/net/mlx4/mlx4_flow.c
@@ -65,6 +65,7 @@
 
 /* PMD headers. */
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -922,24 +923,25 @@ mlx4_drop_get(struct priv *priv)
 		.priv = priv,
 		.refcnt = 1,
 	};
-	drop->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+	drop->cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 	if (!drop->cq)
 		goto error;
-	drop->qp = ibv_create_qp(priv->pd,
-				 &(struct ibv_qp_init_attr){
-					.send_cq = drop->cq,
-					.recv_cq = drop->cq,
-					.qp_type = IBV_QPT_RAW_PACKET,
-				 });
+	drop->qp = mlx4_glue->create_qp
+		(priv->pd,
+		 &(struct ibv_qp_init_attr){
+			.send_cq = drop->cq,
+			.recv_cq = drop->cq,
+			.qp_type = IBV_QPT_RAW_PACKET,
+		 });
 	if (!drop->qp)
 		goto error;
 	priv->drop = drop;
 	return drop;
 error:
 	if (drop->qp)
-		claim_zero(ibv_destroy_qp(drop->qp));
+		claim_zero(mlx4_glue->destroy_qp(drop->qp));
 	if (drop->cq)
-		claim_zero(ibv_destroy_cq(drop->cq));
+		claim_zero(mlx4_glue->destroy_cq(drop->cq));
 	if (drop)
 		rte_free(drop);
 	rte_errno = ENOMEM;
@@ -959,8 +961,8 @@ mlx4_drop_put(struct mlx4_drop *drop)
 	if (--drop->refcnt)
 		return;
 	drop->priv->drop = NULL;
-	claim_zero(ibv_destroy_qp(drop->qp));
-	claim_zero(ibv_destroy_cq(drop->cq));
+	claim_zero(mlx4_glue->destroy_qp(drop->qp));
+	claim_zero(mlx4_glue->destroy_cq(drop->cq));
 	rte_free(drop);
 }
 
@@ -992,7 +994,7 @@ mlx4_flow_toggle(struct priv *priv,
 	if (!enable) {
 		if (!flow->ibv_flow)
 			return 0;
-		claim_zero(ibv_destroy_flow(flow->ibv_flow));
+		claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 		flow->ibv_flow = NULL;
 		if (flow->drop)
 			mlx4_drop_put(priv->drop);
@@ -1005,7 +1007,7 @@ mlx4_flow_toggle(struct priv *priv,
 	    !priv->isolated &&
 	    flow->ibv_attr->priority == MLX4_FLOW_PRIORITY_LAST) {
 		if (flow->ibv_flow) {
-			claim_zero(ibv_destroy_flow(flow->ibv_flow));
+			claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 			flow->ibv_flow = NULL;
 			if (flow->drop)
 				mlx4_drop_put(priv->drop);
@@ -1035,7 +1037,7 @@ mlx4_flow_toggle(struct priv *priv,
 			if (missing ^ !flow->drop)
 				return 0;
 			/* Verbs flow needs updating. */
-			claim_zero(ibv_destroy_flow(flow->ibv_flow));
+			claim_zero(mlx4_glue->destroy_flow(flow->ibv_flow));
 			flow->ibv_flow = NULL;
 			if (flow->drop)
 				mlx4_drop_put(priv->drop);
@@ -1067,7 +1069,7 @@ mlx4_flow_toggle(struct priv *priv,
 	assert(qp);
 	if (flow->ibv_flow)
 		return 0;
-	flow->ibv_flow = ibv_create_flow(qp, flow->ibv_attr);
+	flow->ibv_flow = mlx4_glue->create_flow(qp, flow->ibv_attr);
 	if (flow->ibv_flow)
 		return 0;
 	if (flow->drop)
diff --git a/drivers/net/mlx4/mlx4_glue.c b/drivers/net/mlx4/mlx4_glue.c
new file mode 100644
index 000000000..30797bd2b
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_glue.c
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox
+ */
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx4dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#include "mlx4_glue.h"
+
+static int
+mlx4_glue_fork_init(void)
+{
+	return ibv_fork_init();
+}
+
+static int
+mlx4_glue_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
+{
+	return ibv_get_async_event(context, event);
+}
+
+static void
+mlx4_glue_ack_async_event(struct ibv_async_event *event)
+{
+	ibv_ack_async_event(event);
+}
+
+static struct ibv_pd *
+mlx4_glue_alloc_pd(struct ibv_context *context)
+{
+	return ibv_alloc_pd(context);
+}
+
+static int
+mlx4_glue_dealloc_pd(struct ibv_pd *pd)
+{
+	return ibv_dealloc_pd(pd);
+}
+
+static struct ibv_device **
+mlx4_glue_get_device_list(int *num_devices)
+{
+	return ibv_get_device_list(num_devices);
+}
+
+static void
+mlx4_glue_free_device_list(struct ibv_device **list)
+{
+	ibv_free_device_list(list);
+}
+
+static struct ibv_context *
+mlx4_glue_open_device(struct ibv_device *device)
+{
+	return ibv_open_device(device);
+}
+
+static int
+mlx4_glue_close_device(struct ibv_context *context)
+{
+	return ibv_close_device(context);
+}
+
+static const char *
+mlx4_glue_get_device_name(struct ibv_device *device)
+{
+	return ibv_get_device_name(device);
+}
+
+static int
+mlx4_glue_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context, device_attr);
+}
+
+static int
+mlx4_glue_query_device_ex(struct ibv_context *context,
+			  const struct ibv_query_device_ex_input *input,
+			  struct ibv_device_attr_ex *attr)
+{
+	return ibv_query_device_ex(context, input, attr);
+}
+
+static int
+mlx4_glue_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context, port_num, port_attr);
+}
+
+static const char *
+mlx4_glue_port_state_str(enum ibv_port_state port_state)
+{
+	return ibv_port_state_str(port_state);
+}
+
+static struct ibv_comp_channel *
+mlx4_glue_create_comp_channel(struct ibv_context *context)
+{
+	return ibv_create_comp_channel(context);
+}
+
+static int
+mlx4_glue_destroy_comp_channel(struct ibv_comp_channel *channel)
+{
+	return ibv_destroy_comp_channel(channel);
+}
+
+static struct ibv_cq *
+mlx4_glue_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+		    struct ibv_comp_channel *channel, int comp_vector)
+{
+	return ibv_create_cq(context, cqe, cq_context, channel, comp_vector);
+}
+
+static int
+mlx4_glue_destroy_cq(struct ibv_cq *cq)
+{
+	return ibv_destroy_cq(cq);
+}
+
+static int
+mlx4_glue_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
+		       void **cq_context)
+{
+	return ibv_get_cq_event(channel, cq, cq_context);
+}
+
+static void
+mlx4_glue_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq, nevents);
+}
+
+static struct ibv_flow *
+mlx4_glue_create_flow(struct ibv_qp *qp, struct ibv_flow_attr *flow)
+{
+	return ibv_create_flow(qp, flow);
+}
+
+static int
+mlx4_glue_destroy_flow(struct ibv_flow *flow_id)
+{
+	return ibv_destroy_flow(flow_id);
+}
+
+static struct ibv_qp *
+mlx4_glue_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
+{
+	return ibv_create_qp(pd, qp_init_attr);
+}
+
+static struct ibv_qp *
+mlx4_glue_create_qp_ex(struct ibv_context *context,
+		       struct ibv_qp_init_attr_ex *qp_init_attr_ex)
+{
+	return ibv_create_qp_ex(context, qp_init_attr_ex);
+}
+
+static int
+mlx4_glue_destroy_qp(struct ibv_qp *qp)
+{
+	return ibv_destroy_qp(qp);
+}
+
+static int
+mlx4_glue_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
+{
+	return ibv_modify_qp(qp, attr, attr_mask);
+}
+
+static struct ibv_mr *
+mlx4_glue_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access)
+{
+	return ibv_reg_mr(pd, addr, length, access);
+}
+
+static int
+mlx4_glue_dereg_mr(struct ibv_mr *mr)
+{
+	return ibv_dereg_mr(mr);
+}
+
+static struct ibv_rwq_ind_table *
+mlx4_glue_create_rwq_ind_table(struct ibv_context *context,
+			       struct ibv_rwq_ind_table_init_attr *init_attr)
+{
+	return ibv_create_rwq_ind_table(context, init_attr);
+}
+
+static int
+mlx4_glue_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table)
+{
+	return ibv_destroy_rwq_ind_table(rwq_ind_table);
+}
+
+static struct ibv_wq *
+mlx4_glue_create_wq(struct ibv_context *context,
+		    struct ibv_wq_init_attr *wq_init_attr)
+{
+	return ibv_create_wq(context, wq_init_attr);
+}
+
+static int
+mlx4_glue_destroy_wq(struct ibv_wq *wq)
+{
+	return ibv_destroy_wq(wq);
+}
+static int
+mlx4_glue_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr)
+{
+	return ibv_modify_wq(wq, wq_attr);
+}
+
+static int
+mlx4_glue_dv_init_obj(struct mlx4dv_obj *obj, uint64_t obj_type)
+{
+	return mlx4dv_init_obj(obj, obj_type);
+}
+
+static int
+mlx4_glue_dv_set_context_attr(struct ibv_context *context,
+			      enum mlx4dv_set_ctx_attr_type attr_type,
+			      void *attr)
+{
+	return mlx4dv_set_context_attr(context, attr_type, attr);
+}
+
+const struct mlx4_glue *mlx4_glue = &(const struct mlx4_glue){
+	.fork_init = mlx4_glue_fork_init,
+	.get_async_event = mlx4_glue_get_async_event,
+	.ack_async_event = mlx4_glue_ack_async_event,
+	.alloc_pd = mlx4_glue_alloc_pd,
+	.dealloc_pd = mlx4_glue_dealloc_pd,
+	.get_device_list = mlx4_glue_get_device_list,
+	.free_device_list = mlx4_glue_free_device_list,
+	.open_device = mlx4_glue_open_device,
+	.close_device = mlx4_glue_close_device,
+	.get_device_name = mlx4_glue_get_device_name,
+	.query_device = mlx4_glue_query_device,
+	.query_device_ex = mlx4_glue_query_device_ex,
+	.query_port = mlx4_glue_query_port,
+	.port_state_str = mlx4_glue_port_state_str,
+	.create_comp_channel = mlx4_glue_create_comp_channel,
+	.destroy_comp_channel = mlx4_glue_destroy_comp_channel,
+	.create_cq = mlx4_glue_create_cq,
+	.destroy_cq = mlx4_glue_destroy_cq,
+	.get_cq_event = mlx4_glue_get_cq_event,
+	.ack_cq_events = mlx4_glue_ack_cq_events,
+	.create_flow = mlx4_glue_create_flow,
+	.destroy_flow = mlx4_glue_destroy_flow,
+	.create_qp = mlx4_glue_create_qp,
+	.create_qp_ex = mlx4_glue_create_qp_ex,
+	.destroy_qp = mlx4_glue_destroy_qp,
+	.modify_qp = mlx4_glue_modify_qp,
+	.reg_mr = mlx4_glue_reg_mr,
+	.dereg_mr = mlx4_glue_dereg_mr,
+	.create_rwq_ind_table = mlx4_glue_create_rwq_ind_table,
+	.destroy_rwq_ind_table = mlx4_glue_destroy_rwq_ind_table,
+	.create_wq = mlx4_glue_create_wq,
+	.destroy_wq = mlx4_glue_destroy_wq,
+	.modify_wq = mlx4_glue_modify_wq,
+	.dv_init_obj = mlx4_glue_dv_init_obj,
+	.dv_set_context_attr = mlx4_glue_dv_set_context_attr,
+};
diff --git a/drivers/net/mlx4/mlx4_glue.h b/drivers/net/mlx4/mlx4_glue.h
new file mode 100644
index 000000000..0623511f2
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_glue.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox
+ */
+
+#ifndef MLX4_GLUE_H_
+#define MLX4_GLUE_H_
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx4dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+struct mlx4_glue {
+	int (*fork_init)(void);
+	int (*get_async_event)(struct ibv_context *context,
+			       struct ibv_async_event *event);
+	void (*ack_async_event)(struct ibv_async_event *event);
+	struct ibv_pd *(*alloc_pd)(struct ibv_context *context);
+	int (*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_device **(*get_device_list)(int *num_devices);
+	void (*free_device_list)(struct ibv_device **list);
+	struct ibv_context *(*open_device)(struct ibv_device *device);
+	int (*close_device)(struct ibv_context *context);
+	const char *(*get_device_name)(struct ibv_device *device);
+	int (*query_device)(struct ibv_context *context,
+			    struct ibv_device_attr *device_attr);
+	int (*query_device_ex)(struct ibv_context *context,
+			       const struct ibv_query_device_ex_input *input,
+			       struct ibv_device_attr_ex *attr);
+	int (*query_port)(struct ibv_context *context, uint8_t port_num,
+			  struct ibv_port_attr *port_attr);
+	const char *(*port_state_str)(enum ibv_port_state port_state);
+	struct ibv_comp_channel *(*create_comp_channel)
+		(struct ibv_context *context);
+	int (*destroy_comp_channel)(struct ibv_comp_channel *channel);
+	struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe,
+				    void *cq_context,
+				    struct ibv_comp_channel *channel,
+				    int comp_vector);
+	int (*destroy_cq)(struct ibv_cq *cq);
+	int (*get_cq_event)(struct ibv_comp_channel *channel,
+			    struct ibv_cq **cq, void **cq_context);
+	void (*ack_cq_events)(struct ibv_cq *cq, unsigned int nevents);
+	struct ibv_flow *(*create_flow)(struct ibv_qp *qp,
+					struct ibv_flow_attr *flow);
+	int (*destroy_flow)(struct ibv_flow *flow_id);
+	struct ibv_qp *(*create_qp)(struct ibv_pd *pd,
+				    struct ibv_qp_init_attr *qp_init_attr);
+	struct ibv_qp *(*create_qp_ex)
+		(struct ibv_context *context,
+		 struct ibv_qp_init_attr_ex *qp_init_attr_ex);
+	int (*destroy_qp)(struct ibv_qp *qp);
+	int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+			 int attr_mask);
+	struct ibv_mr *(*reg_mr)(struct ibv_pd *pd, void *addr,
+				 size_t length, int access);
+	int (*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_rwq_ind_table *(*create_rwq_ind_table)
+		(struct ibv_context *context,
+		 struct ibv_rwq_ind_table_init_attr *init_attr);
+	int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table);
+	struct ibv_wq *(*create_wq)(struct ibv_context *context,
+				    struct ibv_wq_init_attr *wq_init_attr);
+	int (*destroy_wq)(struct ibv_wq *wq);
+	int (*modify_wq)(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr);
+	int (*dv_init_obj)(struct mlx4dv_obj *obj, uint64_t obj_type);
+	int (*dv_set_context_attr)(struct ibv_context *context,
+				   enum mlx4dv_set_ctx_attr_type attr_type,
+				   void *attr);
+};
+
+const struct mlx4_glue *mlx4_glue;
+
+#endif /* MLX4_GLUE_H_ */
diff --git a/drivers/net/mlx4/mlx4_intr.c b/drivers/net/mlx4/mlx4_intr.c
index 2ff72188a..d5ab170f9 100644
--- a/drivers/net/mlx4/mlx4_intr.c
+++ b/drivers/net/mlx4/mlx4_intr.c
@@ -57,6 +57,7 @@
 #include <rte_interrupts.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -216,7 +217,7 @@ mlx4_interrupt_handler(struct priv *priv)
 	unsigned int i;
 
 	/* Read all message and acknowledge them. */
-	while (!ibv_get_async_event(priv->ctx, &event)) {
+	while (!mlx4_glue->get_async_event(priv->ctx, &event)) {
 		switch (event.event_type) {
 		case IBV_EVENT_PORT_ACTIVE:
 		case IBV_EVENT_PORT_ERR:
@@ -231,7 +232,7 @@ mlx4_interrupt_handler(struct priv *priv)
 			DEBUG("event type %d on physical port %d not handled",
 			      event.event_type, event.element.port_num);
 		}
-		ibv_ack_async_event(&event);
+		mlx4_glue->ack_async_event(&event);
 	}
 	for (i = 0; i != RTE_DIM(caught); ++i)
 		if (caught[i])
@@ -354,7 +355,8 @@ mlx4_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
 	if (!rxq || !rxq->channel) {
 		ret = EINVAL;
 	} else {
-		ret = ibv_get_cq_event(rxq->cq->channel, &ev_cq, &ev_ctx);
+		ret = mlx4_glue->get_cq_event(rxq->cq->channel, &ev_cq,
+					      &ev_ctx);
 		if (ret || ev_cq != rxq->cq)
 			ret = EINVAL;
 	}
@@ -364,7 +366,7 @@ mlx4_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
 		     idx);
 	} else {
 		rxq->mcq.arm_sn++;
-		ibv_ack_cq_events(rxq->cq, 1);
+		mlx4_glue->ack_cq_events(rxq->cq, 1);
 	}
 	return -ret;
 }
diff --git a/drivers/net/mlx4/mlx4_mr.c b/drivers/net/mlx4/mlx4_mr.c
index 2a3e2695b..493c00867 100644
--- a/drivers/net/mlx4/mlx4_mr.c
+++ b/drivers/net/mlx4/mlx4_mr.c
@@ -60,6 +60,7 @@
 #include <rte_mempool.h>
 #include <rte_spinlock.h>
 
+#include "mlx4_glue.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
@@ -200,8 +201,8 @@ mlx4_mr_get(struct priv *priv, struct rte_mempool *mp)
 		.end = end,
 		.refcnt = 1,
 		.priv = priv,
-		.mr = ibv_reg_mr(priv->pd, (void *)start, end - start,
-				 IBV_ACCESS_LOCAL_WRITE),
+		.mr = mlx4_glue->reg_mr(priv->pd, (void *)start, end - start,
+					IBV_ACCESS_LOCAL_WRITE),
 		.mp = mp,
 	};
 	if (mr->mr) {
@@ -240,7 +241,7 @@ mlx4_mr_put(struct mlx4_mr *mr)
 	if (--mr->refcnt)
 		goto release;
 	LIST_REMOVE(mr, next);
-	claim_zero(ibv_dereg_mr(mr->mr));
+	claim_zero(mlx4_glue->dereg_mr(mr->mr));
 	rte_free(mr);
 release:
 	rte_spinlock_unlock(&priv->mr_lock);
diff --git a/drivers/net/mlx4/mlx4_rxq.c b/drivers/net/mlx4/mlx4_rxq.c
index 163598765..bf60d2fc8 100644
--- a/drivers/net/mlx4/mlx4_rxq.c
+++ b/drivers/net/mlx4/mlx4_rxq.c
@@ -62,6 +62,7 @@
 #include <rte_mempool.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_flow.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -231,7 +232,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		}
 		ind_tbl[i] = rxq->wq;
 	}
-	rss->ind = ibv_create_rwq_ind_table
+	rss->ind = mlx4_glue->create_rwq_ind_table
 		(priv->ctx,
 		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = rte_log2_u32(RTE_DIM(ind_tbl)),
@@ -243,7 +244,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "RSS indirection table creation failure";
 		goto error;
 	}
-	rss->qp = ibv_create_qp_ex
+	rss->qp = mlx4_glue->create_qp_ex
 		(priv->ctx,
 		 &(struct ibv_qp_init_attr_ex){
 			.comp_mask = (IBV_QP_INIT_ATTR_PD |
@@ -264,7 +265,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "RSS hash QP creation failure";
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(rss->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_INIT,
@@ -275,7 +276,7 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 		msg = "failed to switch RSS hash QP to INIT state";
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(rss->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTR,
@@ -288,11 +289,11 @@ mlx4_rss_attach(struct mlx4_rss *rss)
 	return 0;
 error:
 	if (rss->qp) {
-		claim_zero(ibv_destroy_qp(rss->qp));
+		claim_zero(mlx4_glue->destroy_qp(rss->qp));
 		rss->qp = NULL;
 	}
 	if (rss->ind) {
-		claim_zero(ibv_destroy_rwq_ind_table(rss->ind));
+		claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind));
 		rss->ind = NULL;
 	}
 	while (i--)
@@ -325,9 +326,9 @@ mlx4_rss_detach(struct mlx4_rss *rss)
 	assert(rss->ind);
 	if (--rss->usecnt)
 		return;
-	claim_zero(ibv_destroy_qp(rss->qp));
+	claim_zero(mlx4_glue->destroy_qp(rss->qp));
 	rss->qp = NULL;
-	claim_zero(ibv_destroy_rwq_ind_table(rss->ind));
+	claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind));
 	rss->ind = NULL;
 	for (i = 0; i != rss->queues; ++i)
 		mlx4_rxq_detach(priv->dev->data->rx_queues[rss->queue_id[i]]);
@@ -364,9 +365,10 @@ mlx4_rss_init(struct priv *priv)
 	int ret;
 
 	/* Prepare range for RSS contexts before creating the first WQ. */
-	ret = mlx4dv_set_context_attr(priv->ctx,
-				      MLX4DV_SET_CTX_ATTR_LOG_WQS_RANGE_SZ,
-				      &log2_range);
+	ret = mlx4_glue->dv_set_context_attr
+		(priv->ctx,
+		 MLX4DV_SET_CTX_ATTR_LOG_WQS_RANGE_SZ,
+		 &log2_range);
 	if (ret) {
 		ERROR("cannot set up range size for RSS context to %u"
 		      " (for %u Rx queues), error: %s",
@@ -402,13 +404,13 @@ mlx4_rss_init(struct priv *priv)
 		 * sequentially and are guaranteed to never be reused in the
 		 * same context by the underlying implementation.
 		 */
-		cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+		cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 		if (!cq) {
 			ret = ENOMEM;
 			msg = "placeholder CQ creation failure";
 			goto error;
 		}
-		wq = ibv_create_wq
+		wq = mlx4_glue->create_wq
 			(priv->ctx,
 			 &(struct ibv_wq_init_attr){
 				.wq_type = IBV_WQT_RQ,
@@ -419,11 +421,11 @@ mlx4_rss_init(struct priv *priv)
 			 });
 		if (wq) {
 			wq_num = wq->wq_num;
-			claim_zero(ibv_destroy_wq(wq));
+			claim_zero(mlx4_glue->destroy_wq(wq));
 		} else {
 			wq_num = 0; /* Shut up GCC 4.8 warnings. */
 		}
-		claim_zero(ibv_destroy_cq(cq));
+		claim_zero(mlx4_glue->destroy_cq(cq));
 		if (!wq) {
 			ret = ENOMEM;
 			msg = "placeholder WQ creation failure";
@@ -522,13 +524,14 @@ mlx4_rxq_attach(struct rxq *rxq)
 	int ret;
 
 	assert(rte_is_power_of_2(elts_n));
-	cq = ibv_create_cq(priv->ctx, elts_n / sges_n, NULL, rxq->channel, 0);
+	cq = mlx4_glue->create_cq(priv->ctx, elts_n / sges_n, NULL,
+				  rxq->channel, 0);
 	if (!cq) {
 		ret = ENOMEM;
 		msg = "CQ creation failure";
 		goto error;
 	}
-	wq = ibv_create_wq
+	wq = mlx4_glue->create_wq
 		(priv->ctx,
 		 &(struct ibv_wq_init_attr){
 			.wq_type = IBV_WQT_RQ,
@@ -542,7 +545,7 @@ mlx4_rxq_attach(struct rxq *rxq)
 		msg = "WQ creation failure";
 		goto error;
 	}
-	ret = ibv_modify_wq
+	ret = mlx4_glue->modify_wq
 		(wq,
 		 &(struct ibv_wq_attr){
 			.attr_mask = IBV_WQ_ATTR_STATE,
@@ -557,7 +560,7 @@ mlx4_rxq_attach(struct rxq *rxq)
 	mlxdv.cq.out = &dv_cq;
 	mlxdv.rwq.in = wq;
 	mlxdv.rwq.out = &dv_rwq;
-	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_RWQ | MLX4DV_OBJ_CQ);
+	ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_RWQ | MLX4DV_OBJ_CQ);
 	if (ret) {
 		msg = "failed to obtain device information from WQ/CQ objects";
 		goto error;
@@ -619,9 +622,9 @@ mlx4_rxq_attach(struct rxq *rxq)
 	return 0;
 error:
 	if (wq)
-		claim_zero(ibv_destroy_wq(wq));
+		claim_zero(mlx4_glue->destroy_wq(wq));
 	if (cq)
-		claim_zero(ibv_destroy_cq(cq));
+		claim_zero(mlx4_glue->destroy_cq(cq));
 	rte_errno = ret;
 	ERROR("error while attaching Rx queue %p: %s: %s",
 	      (void *)rxq, msg, strerror(ret));
@@ -649,9 +652,9 @@ mlx4_rxq_detach(struct rxq *rxq)
 	memset(&rxq->mcq, 0, sizeof(rxq->mcq));
 	rxq->rq_db = NULL;
 	rxq->wqes = NULL;
-	claim_zero(ibv_destroy_wq(rxq->wq));
+	claim_zero(mlx4_glue->destroy_wq(rxq->wq));
 	rxq->wq = NULL;
-	claim_zero(ibv_destroy_cq(rxq->cq));
+	claim_zero(mlx4_glue->destroy_cq(rxq->cq));
 	rxq->cq = NULL;
 	DEBUG("%p: freeing Rx queue elements", (void *)rxq);
 	for (i = 0; (i != RTE_DIM(*elts)); ++i) {
@@ -879,7 +882,7 @@ mlx4_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		goto error;
 	}
 	if (dev->data->dev_conf.intr_conf.rxq) {
-		rxq->channel = ibv_create_comp_channel(priv->ctx);
+		rxq->channel = mlx4_glue->create_comp_channel(priv->ctx);
 		if (rxq->channel == NULL) {
 			rte_errno = ENOMEM;
 			ERROR("%p: Rx interrupt completion channel creation"
@@ -934,7 +937,7 @@ mlx4_rx_queue_release(void *dpdk_rxq)
 	assert(!rxq->wqes);
 	assert(!rxq->rq_db);
 	if (rxq->channel)
-		claim_zero(ibv_destroy_comp_channel(rxq->channel));
+		claim_zero(mlx4_glue->destroy_comp_channel(rxq->channel));
 	if (rxq->mr)
 		mlx4_mr_put(rxq->mr);
 	rte_free(rxq);
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 2bd4b9cb6..5e4d701cd 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -60,6 +60,7 @@
 #include <rte_mempool.h>
 
 #include "mlx4.h"
+#include "mlx4_glue.h"
 #include "mlx4_prm.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
@@ -350,7 +351,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		.lb = !!priv->vf,
 		.bounce_buf = bounce_buf,
 	};
-	txq->cq = ibv_create_cq(priv->ctx, desc, NULL, NULL, 0);
+	txq->cq = mlx4_glue->create_cq(priv->ctx, desc, NULL, NULL, 0);
 	if (!txq->cq) {
 		rte_errno = ENOMEM;
 		ERROR("%p: CQ creation failure: %s",
@@ -370,7 +371,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		/* No completion events must occur by default. */
 		.sq_sig_all = 0,
 	};
-	txq->qp = ibv_create_qp(priv->pd, &qp_init_attr);
+	txq->qp = mlx4_glue->create_qp(priv->pd, &qp_init_attr);
 	if (!txq->qp) {
 		rte_errno = errno ? errno : EINVAL;
 		ERROR("%p: QP creation failure: %s",
@@ -378,7 +379,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		goto error;
 	}
 	txq->max_inline = qp_init_attr.cap.max_inline_data;
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_INIT,
@@ -391,7 +392,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTR,
@@ -403,7 +404,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = ibv_modify_qp
+	ret = mlx4_glue->modify_qp
 		(txq->qp,
 		 &(struct ibv_qp_attr){
 			.qp_state = IBV_QPS_RTS,
@@ -420,7 +421,7 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 	mlxdv.cq.out = &dv_cq;
 	mlxdv.qp.in = txq->qp;
 	mlxdv.qp.out = &dv_qp;
-	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
+	ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
 	if (ret) {
 		rte_errno = EINVAL;
 		ERROR("%p: failed to obtain information needed for"
@@ -470,9 +471,9 @@ mlx4_tx_queue_release(void *dpdk_txq)
 		}
 	mlx4_txq_free_elts(txq);
 	if (txq->qp)
-		claim_zero(ibv_destroy_qp(txq->qp));
+		claim_zero(mlx4_glue->destroy_qp(txq->qp));
 	if (txq->cq)
-		claim_zero(ibv_destroy_cq(txq->cq));
+		claim_zero(mlx4_glue->destroy_cq(txq->cq));
 	for (i = 0; i != RTE_DIM(txq->mp2mr); ++i) {
 		if (!txq->mp2mr[i].mp)
 			break;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-30 15:34     ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  2018-01-30 15:34       ` [PATCH v4 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
@ 2018-01-30 15:34       ` Adrien Mazarguil
  2018-01-30 17:54         ` Marcelo Ricardo Leitner
  2018-01-30 15:34       ` [PATCH v4 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
                         ` (2 subsequent siblings)
  4 siblings, 1 reply; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-30 15:34 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

When mlx4 is not compiled directly as an independent shared object (e.g.
CONFIG_RTE_BUILD_SHARED_LIB not enabled for performance reasons), DPDK
applications inherit its dependencies on libibverbs and libmlx4 through
rte.app.mk.

This is an issue both when DPDK is delivered as a binary package (Linux
distributions) and for end users because rdma-core then propagates as a
mandatory dependency for everything.

Application writers relying on binary DPDK packages are not necessarily
aware of this fact and may end up delivering packages with broken
dependencies.

This patch therefore introduces an intermediate internal plug-in
hard-linked with rdma-core (to preserve symbol versioning) loaded by the
PMD through dlopen(), so that a missing rdma-core does not cause unresolved
symbols, allowing applications to start normally.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 config/common_base        |  1 +
 doc/guides/nics/mlx4.rst  | 13 +++++++++++
 drivers/net/mlx4/Makefile | 29 +++++++++++++++++++++++++
 drivers/net/mlx4/mlx4.c   | 49 ++++++++++++++++++++++++++++++++++++++++++
 mk/rte.app.mk             |  4 ++++
 5 files changed, 96 insertions(+)

diff --git a/config/common_base b/config/common_base
index 170a38939..6df20be0e 100644
--- a/config/common_base
+++ b/config/common_base
@@ -298,6 +298,7 @@ CONFIG_RTE_LIBRTE_AVF_16BYTE_RX_DESC=n
 #
 CONFIG_RTE_LIBRTE_MLX4_PMD=n
 CONFIG_RTE_LIBRTE_MLX4_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS=n
 CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8
 
 #
diff --git a/doc/guides/nics/mlx4.rst b/doc/guides/nics/mlx4.rst
index cab45dfe8..88161781c 100644
--- a/doc/guides/nics/mlx4.rst
+++ b/doc/guides/nics/mlx4.rst
@@ -86,6 +86,19 @@ These options can be modified in the ``.config`` file.
 
   Toggle compilation of librte_pmd_mlx4 itself.
 
+- ``CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS`` (default **n**)
+
+  Build PMD with additional code to make it loadable without hard
+  dependencies on **libibverbs** nor **libmlx4**, which may not be installed
+  on the target system.
+
+  In this mode, their presence is still required for it to run properly,
+  however their absence won't prevent a DPDK application from starting (with
+  ``CONFIG_RTE_BUILD_SHARED_LIB`` disabled) and they won't show up as
+  missing with ``ldd(1)``.
+
+  This option has no performance impact.
+
 - ``CONFIG_RTE_LIBRTE_MLX4_DEBUG`` (default **n**)
 
   Toggle debugging code and stricter compilation flags. Enabling this option
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1d33c38ed..c004ac71c 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -33,12 +33,15 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 # Library name.
 LIB = librte_pmd_mlx4.a
+LIB_GLUE = librte_pmd_mlx4_glue.so
 
 # Sources.
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_flow.c
+ifneq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_glue.c
+endif
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_intr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxq.c
@@ -46,6 +49,10 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_txq.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4_utils.c
 
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+INSTALL-$(CONFIG_RTE_LIBRTE_MLX4_PMD)-lib += $(LIB_GLUE)
+endif
+
 # Basic CFLAGS.
 CFLAGS += -O3
 CFLAGS += -std=c11 -Wall -Wextra
@@ -55,7 +62,13 @@ CFLAGS += -D_BSD_SOURCE
 CFLAGS += -D_DEFAULT_SOURCE
 CFLAGS += -D_XOPEN_SOURCE=600
 CFLAGS += $(WERROR_FLAGS)
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+CFLAGS += -DMLX4_GLUE='"$(LIB_GLUE)"'
+CFLAGS_mlx4_glue.o += -fPIC
+LDLIBS += -ldl
+else
 LDLIBS += -libverbs -lmlx4
+endif
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
@@ -109,7 +122,23 @@ mlx4_autoconf.h: mlx4_autoconf.h.new
 
 $(SRCS-$(CONFIG_RTE_LIBRTE_MLX4_PMD):.c=.o): mlx4_autoconf.h
 
+# Generate dependency plug-in for rdma-core when the PMD must not be linked
+# directly, so that applications do not inherit this dependency.
+
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+
+$(LIB): $(LIB_GLUE)
+
+$(LIB_GLUE): mlx4_glue.o
+	$Q $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) \
+		-s -shared -o $@ $< -libverbs -lmlx4
+
+mlx4_glue.o: mlx4_autoconf.h
+
+endif
+
 clean_mlx4: FORCE
 	$Q rm -f -- mlx4_autoconf.h mlx4_autoconf.h.new
+	$Q rm -f -- mlx4_glue.o $(LIB_GLUE)
 
 clean: clean_mlx4
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index f304359bb..12e6b431c 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -37,6 +37,7 @@
  */
 
 #include <assert.h>
+#include <dlfcn.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <stddef.h>
@@ -44,6 +45,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 /* Verbs headers do not support -pedantic. */
 #ifdef PEDANTIC
@@ -55,6 +57,7 @@
 #endif
 
 #include <rte_common.h>
+#include <rte_config.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
 #include <rte_ethdev_driver.h>
@@ -724,6 +727,47 @@ static struct rte_pci_driver mlx4_driver = {
 		     RTE_PCI_DRV_INTR_RMV,
 };
 
+#ifdef RTE_LIBRTE_MLX4_DLOPEN_DEPS
+
+/**
+ * Initialization routine for run-time dependency on rdma-core.
+ */
+static int
+mlx4_glue_init(void)
+{
+	void *handle = NULL;
+	void **sym;
+	const char *dlmsg;
+
+	handle = dlopen(MLX4_GLUE, RTLD_LAZY);
+	if (!handle) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot load glue library: %s", dlmsg);
+		goto glue_error;
+	}
+	sym = dlsym(handle, "mlx4_glue");
+	if (!sym || !*sym) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot resolve glue symbol: %s", dlmsg);
+		goto glue_error;
+	}
+	mlx4_glue = *sym;
+	return 0;
+glue_error:
+	if (handle)
+		dlclose(handle);
+	ERROR("cannot initialize PMD due to missing run-time"
+	      " dependency on rdma-core libraries (libibverbs,"
+	      " libmlx4)");
+	return -rte_errno;
+}
+
+#endif
+
 /**
  * Driver initialization routine.
  */
@@ -744,6 +788,11 @@ rte_mlx4_pmd_init(void)
 	 * using this PMD, which is not supported in forked processes.
 	 */
 	setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
+#ifdef RTE_LIBRTE_MLX4_DLOPEN_DEPS
+	if (mlx4_glue_init())
+		return;
+	assert(mlx4_glue);
+#endif
 	mlx4_glue->fork_init();
 	rte_pci_register(&mlx4_driver);
 }
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 0169f3f5b..fdbe36630 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -143,7 +143,11 @@ ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KNI)        += -lrte_pmd_kni
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio
+ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -ldl
+else
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs -lmlx4
+endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs -lmlx5
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 3/4] net/mlx5: move rdma-core calls to separate file
  2018-01-30 15:34     ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
  2018-01-30 15:34       ` [PATCH v4 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
  2018-01-30 15:34       ` [PATCH v4 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-30 15:34       ` Adrien Mazarguil
  2018-01-30 15:34       ` [PATCH v4 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
  2018-01-31 10:13       ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Shahaf Shuler
  4 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-30 15:34 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

From: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>

This lays the groundwork for externalizing rdma-core as an optional
run-time dependency instead of a mandatory one.

No functional change.

Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 drivers/net/mlx5/Makefile      |   1 +
 drivers/net/mlx5/mlx5.c        |  44 ++---
 drivers/net/mlx5/mlx5_ethdev.c |   7 +-
 drivers/net/mlx5/mlx5_flow.c   |  92 +++++-----
 drivers/net/mlx5/mlx5_glue.c   | 352 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h   | 106 +++++++++++
 drivers/net/mlx5/mlx5_mr.c     |   7 +-
 drivers/net/mlx5/mlx5_rxq.c    |  54 +++---
 drivers/net/mlx5/mlx5_txq.c    |  22 ++-
 drivers/net/mlx5/mlx5_vlan.c   |  13 +-
 10 files changed, 586 insertions(+), 112 deletions(-)

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index a3984eb9f..bdec30692 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -53,6 +53,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
 
 # Basic CFLAGS.
 CFLAGS += -O3
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 5a959f7c5..b911d0ad4 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -65,6 +65,7 @@
 #include "mlx5_rxtx.h"
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
+#include "mlx5_glue.h"
 
 /* Device parameter to enable RX completion queue compression. */
 #define MLX5_RXQ_CQE_COMP_EN "rxq_cqe_comp_en"
@@ -218,8 +219,8 @@ mlx5_dev_close(struct rte_eth_dev *dev)
 	}
 	if (priv->pd != NULL) {
 		assert(priv->ctx != NULL);
-		claim_zero(ibv_dealloc_pd(priv->pd));
-		claim_zero(ibv_close_device(priv->ctx));
+		claim_zero(mlx5_glue->dealloc_pd(priv->pd));
+		claim_zero(mlx5_glue->close_device(priv->ctx));
 	} else
 		assert(priv->ctx == NULL);
 	if (priv->rss_conf.rss_key != NULL)
@@ -625,7 +626,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 	/* Save PCI address. */
 	mlx5_dev[idx].pci_addr = pci_dev->addr;
-	list = ibv_get_device_list(&i);
+	list = mlx5_glue->get_device_list(&i);
 	if (list == NULL) {
 		assert(errno);
 		if (errno == ENOSYS)
@@ -675,12 +676,12 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		     " (SR-IOV: %s)",
 		     list[i]->name,
 		     sriov ? "true" : "false");
-		attr_ctx = ibv_open_device(list[i]);
+		attr_ctx = mlx5_glue->open_device(list[i]);
 		err = errno;
 		break;
 	}
 	if (attr_ctx == NULL) {
-		ibv_free_device_list(list);
+		mlx5_glue->free_device_list(list);
 		switch (err) {
 		case 0:
 			ERROR("cannot access device, is mlx5_ib loaded?");
@@ -699,7 +700,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 	 * Multi-packet send is supported by ConnectX-4 Lx PF as well
 	 * as all ConnectX-5 devices.
 	 */
-	mlx5dv_query_device(attr_ctx, &attrs_out);
+	mlx5_glue->dv_query_device(attr_ctx, &attrs_out);
 	if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_MPW_ALLOWED) {
 		if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_ENHANCED_MPW) {
 			DEBUG("Enhanced MPW is supported");
@@ -717,7 +718,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		cqe_comp = 0;
 	else
 		cqe_comp = 1;
-	if (ibv_query_device_ex(attr_ctx, NULL, &device_attr))
+	if (mlx5_glue->query_device_ex(attr_ctx, NULL, &device_attr))
 		goto error;
 	INFO("%u port(s) detected", device_attr.orig_attr.phys_port_cnt);
 
@@ -794,15 +795,15 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 		DEBUG("using port %u (%08" PRIx32 ")", port, test);
 
-		ctx = ibv_open_device(ibv_dev);
+		ctx = mlx5_glue->open_device(ibv_dev);
 		if (ctx == NULL) {
 			err = ENODEV;
 			goto port_error;
 		}
 
-		ibv_query_device_ex(ctx, NULL, &device_attr);
+		mlx5_glue->query_device_ex(ctx, NULL, &device_attr);
 		/* Check port status. */
-		err = ibv_query_port(ctx, port, &port_attr);
+		err = mlx5_glue->query_port(ctx, port, &port_attr);
 		if (err) {
 			ERROR("port query failed: %s", strerror(err));
 			goto port_error;
@@ -817,11 +818,11 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 		if (port_attr.state != IBV_PORT_ACTIVE)
 			DEBUG("port %d is not active: \"%s\" (%d)",
-			      port, ibv_port_state_str(port_attr.state),
+			      port, mlx5_glue->port_state_str(port_attr.state),
 			      port_attr.state);
 
 		/* Allocate protection domain. */
-		pd = ibv_alloc_pd(ctx);
+		pd = mlx5_glue->alloc_pd(ctx);
 		if (pd == NULL) {
 			ERROR("PD allocation failure");
 			err = ENOMEM;
@@ -853,7 +854,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			      strerror(err));
 			goto port_error;
 		}
-		if (ibv_query_device_ex(ctx, NULL, &device_attr_ex)) {
+		if (mlx5_glue->query_device_ex(ctx, NULL, &device_attr_ex)) {
 			ERROR("ibv_query_device_ex() failed");
 			goto port_error;
 		}
@@ -873,7 +874,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
 		config.flow_counter_en = !!(device_attr.max_counter_sets);
-		ibv_describe_counter_set(ctx, 0, &cs_desc);
+		mlx5_glue->describe_counter_set(ctx, 0, &cs_desc);
 		DEBUG("counter type = %d, num of cs = %ld, attributes = %d",
 		      cs_desc.counter_type, cs_desc.num_of_cs,
 		      cs_desc.attributes);
@@ -984,8 +985,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 			.free = &mlx5_free_verbs_buf,
 			.data = priv,
 		};
-		mlx5dv_set_context_attr(ctx, MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
-					(void *)((uintptr_t)&alctr));
+		mlx5_glue->dv_set_context_attr(ctx,
+					       MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
+					       (void *)((uintptr_t)&alctr));
 
 		/* Bring Ethernet device up. */
 		DEBUG("forcing Ethernet interface up");
@@ -998,9 +1000,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 		if (priv)
 			rte_free(priv);
 		if (pd)
-			claim_zero(ibv_dealloc_pd(pd));
+			claim_zero(mlx5_glue->dealloc_pd(pd));
 		if (ctx)
-			claim_zero(ibv_close_device(ctx));
+			claim_zero(mlx5_glue->close_device(ctx));
 		break;
 	}
 
@@ -1019,9 +1021,9 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
 
 error:
 	if (attr_ctx)
-		claim_zero(ibv_close_device(attr_ctx));
+		claim_zero(mlx5_glue->close_device(attr_ctx));
 	if (list)
-		ibv_free_device_list(list);
+		mlx5_glue->free_device_list(list);
 	assert(err >= 0);
 	return -err;
 }
@@ -1092,7 +1094,7 @@ rte_mlx5_pmd_init(void)
 	/* Match the size of Rx completion entry to the size of a cacheline. */
 	if (RTE_CACHE_LINE_SIZE == 128)
 		setenv("MLX5_CQE_SIZE", "128", 0);
-	ibv_fork_init();
+	mlx5_glue->fork_init();
 	rte_pci_register(&mlx5_driver);
 }
 
diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c
index 83657f509..cbc735a8b 100644
--- a/drivers/net/mlx5/mlx5_ethdev.c
+++ b/drivers/net/mlx5/mlx5_ethdev.c
@@ -64,6 +64,7 @@
 #include <rte_malloc.h>
 
 #include "mlx5.h"
+#include "mlx5_glue.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_utils.h"
 
@@ -1261,7 +1262,7 @@ priv_dev_status_handler(struct priv *priv)
 
 	/* Read all message and acknowledge them. */
 	for (;;) {
-		if (ibv_get_async_event(priv->ctx, &event))
+		if (mlx5_glue->get_async_event(priv->ctx, &event))
 			break;
 		if ((event.event_type == IBV_EVENT_PORT_ACTIVE ||
 			event.event_type == IBV_EVENT_PORT_ERR) &&
@@ -1273,7 +1274,7 @@ priv_dev_status_handler(struct priv *priv)
 		else
 			DEBUG("event type %d on port %d not handled",
 			      event.event_type, event.element.port_num);
-		ibv_ack_async_event(&event);
+		mlx5_glue->ack_async_event(&event);
 	}
 	if (ret & (1 << RTE_ETH_EVENT_INTR_LSC))
 		if (priv_link_status_update(priv))
@@ -1559,7 +1560,7 @@ mlx5_is_removed(struct rte_eth_dev *dev)
 	struct ibv_device_attr device_attr;
 	struct priv *priv = dev->data->dev_private;
 
-	if (ibv_query_device(priv->ctx, &device_attr) == EIO)
+	if (mlx5_glue->query_device(priv->ctx, &device_attr) == EIO)
 		return 1;
 	return 0;
 }
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index bf8eff8a5..800ec9f07 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -53,6 +53,7 @@
 #include "mlx5.h"
 #include "mlx5_defs.h"
 #include "mlx5_prm.h"
+#include "mlx5_glue.h"
 
 /* Define minimal priority for control plane flows. */
 #define MLX5_CTRL_FLOW_PRIORITY 4
@@ -62,22 +63,9 @@
 #define MLX5_IPV6 6
 
 #ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
-struct ibv_counter_set_init_attr {
-	int dummy;
-};
 struct ibv_flow_spec_counter_action {
 	int dummy;
 };
-struct ibv_counter_set {
-	int dummy;
-};
-
-static inline int
-ibv_destroy_counter_set(struct ibv_counter_set *cs)
-{
-	(void)cs;
-	return -ENOTSUP;
-}
 #endif
 
 /* Dev ops structure defined in mlx5.c */
@@ -1649,7 +1637,7 @@ mlx5_flow_create_count(struct priv *priv __rte_unused,
 	};
 
 	init_attr.counter_set_id = 0;
-	parser->cs = ibv_create_counter_set(priv->ctx, &init_attr);
+	parser->cs = mlx5_glue->create_counter_set(priv->ctx, &init_attr);
 	if (!parser->cs)
 		return EINVAL;
 	counter.counter_set_handle = parser->cs->handle;
@@ -1702,8 +1690,8 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 		return 0;
 	parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
 	flow->frxq[HASH_RXQ_ETH].ibv_flow =
-		ibv_create_flow(priv->flow_drop_queue->qp,
-				flow->frxq[HASH_RXQ_ETH].ibv_attr);
+		mlx5_glue->create_flow(priv->flow_drop_queue->qp,
+				       flow->frxq[HASH_RXQ_ETH].ibv_attr);
 	if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
 		rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
 				   NULL, "flow rule creation failure");
@@ -1714,7 +1702,8 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 error:
 	assert(flow);
 	if (flow->frxq[HASH_RXQ_ETH].ibv_flow) {
-		claim_zero(ibv_destroy_flow(flow->frxq[HASH_RXQ_ETH].ibv_flow));
+		claim_zero(mlx5_glue->destroy_flow
+			   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 		flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
 	}
 	if (flow->frxq[HASH_RXQ_ETH].ibv_attr) {
@@ -1722,7 +1711,7 @@ priv_flow_create_action_queue_drop(struct priv *priv,
 		flow->frxq[HASH_RXQ_ETH].ibv_attr = NULL;
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 		parser->cs = NULL;
 	}
@@ -1826,8 +1815,8 @@ priv_flow_create_action_queue(struct priv *priv,
 		if (!flow->frxq[i].hrxq)
 			continue;
 		flow->frxq[i].ibv_flow =
-			ibv_create_flow(flow->frxq[i].hrxq->qp,
-					flow->frxq[i].ibv_attr);
+			mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
+					       flow->frxq[i].ibv_attr);
 		if (!flow->frxq[i].ibv_flow) {
 			rte_flow_error_set(error, ENOMEM,
 					   RTE_FLOW_ERROR_TYPE_HANDLE,
@@ -1853,7 +1842,7 @@ priv_flow_create_action_queue(struct priv *priv,
 		if (flow->frxq[i].ibv_flow) {
 			struct ibv_flow *ibv_flow = flow->frxq[i].ibv_flow;
 
-			claim_zero(ibv_destroy_flow(ibv_flow));
+			claim_zero(mlx5_glue->destroy_flow(ibv_flow));
 		}
 		if (flow->frxq[i].hrxq)
 			mlx5_priv_hrxq_release(priv, flow->frxq[i].hrxq);
@@ -1861,7 +1850,7 @@ priv_flow_create_action_queue(struct priv *priv,
 			rte_free(flow->frxq[i].ibv_attr);
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 		parser->cs = NULL;
 	}
@@ -2039,7 +2028,7 @@ priv_flow_destroy(struct priv *priv,
 free:
 	if (flow->drop) {
 		if (flow->frxq[HASH_RXQ_ETH].ibv_flow)
-			claim_zero(ibv_destroy_flow
+			claim_zero(mlx5_glue->destroy_flow
 				   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 		rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
 	} else {
@@ -2047,7 +2036,8 @@ priv_flow_destroy(struct priv *priv,
 			struct mlx5_flow *frxq = &flow->frxq[i];
 
 			if (frxq->ibv_flow)
-				claim_zero(ibv_destroy_flow(frxq->ibv_flow));
+				claim_zero(mlx5_glue->destroy_flow
+					   (frxq->ibv_flow));
 			if (frxq->hrxq)
 				mlx5_priv_hrxq_release(priv, frxq->hrxq);
 			if (frxq->ibv_attr)
@@ -2055,7 +2045,7 @@ priv_flow_destroy(struct priv *priv,
 		}
 	}
 	if (flow->cs) {
-		claim_zero(ibv_destroy_counter_set(flow->cs));
+		claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
 		flow->cs = NULL;
 	}
 	TAILQ_REMOVE(list, flow, next);
@@ -2103,35 +2093,38 @@ priv_flow_create_drop_queue(struct priv *priv)
 		WARN("cannot allocate memory for drop queue");
 		goto error;
 	}
-	fdq->cq = ibv_create_cq(priv->ctx, 1, NULL, NULL, 0);
+	fdq->cq = mlx5_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
 	if (!fdq->cq) {
 		WARN("cannot allocate CQ for drop queue");
 		goto error;
 	}
-	fdq->wq = ibv_create_wq(priv->ctx,
-			&(struct ibv_wq_init_attr){
+	fdq->wq = mlx5_glue->create_wq
+		(priv->ctx,
+		 &(struct ibv_wq_init_attr){
 			.wq_type = IBV_WQT_RQ,
 			.max_wr = 1,
 			.max_sge = 1,
 			.pd = priv->pd,
 			.cq = fdq->cq,
-			});
+		 });
 	if (!fdq->wq) {
 		WARN("cannot allocate WQ for drop queue");
 		goto error;
 	}
-	fdq->ind_table = ibv_create_rwq_ind_table(priv->ctx,
-			&(struct ibv_rwq_ind_table_init_attr){
+	fdq->ind_table = mlx5_glue->create_rwq_ind_table
+		(priv->ctx,
+		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = 0,
 			.ind_tbl = &fdq->wq,
 			.comp_mask = 0,
-			});
+		 });
 	if (!fdq->ind_table) {
 		WARN("cannot allocate indirection table for drop queue");
 		goto error;
 	}
-	fdq->qp = ibv_create_qp_ex(priv->ctx,
-		&(struct ibv_qp_init_attr_ex){
+	fdq->qp = mlx5_glue->create_qp_ex
+		(priv->ctx,
+		 &(struct ibv_qp_init_attr_ex){
 			.qp_type = IBV_QPT_RAW_PACKET,
 			.comp_mask =
 				IBV_QP_INIT_ATTR_PD |
@@ -2146,7 +2139,7 @@ priv_flow_create_drop_queue(struct priv *priv)
 				},
 			.rwq_ind_tbl = fdq->ind_table,
 			.pd = priv->pd
-		});
+		 });
 	if (!fdq->qp) {
 		WARN("cannot allocate QP for drop queue");
 		goto error;
@@ -2155,13 +2148,13 @@ priv_flow_create_drop_queue(struct priv *priv)
 	return 0;
 error:
 	if (fdq->qp)
-		claim_zero(ibv_destroy_qp(fdq->qp));
+		claim_zero(mlx5_glue->destroy_qp(fdq->qp));
 	if (fdq->ind_table)
-		claim_zero(ibv_destroy_rwq_ind_table(fdq->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
 	if (fdq->wq)
-		claim_zero(ibv_destroy_wq(fdq->wq));
+		claim_zero(mlx5_glue->destroy_wq(fdq->wq));
 	if (fdq->cq)
-		claim_zero(ibv_destroy_cq(fdq->cq));
+		claim_zero(mlx5_glue->destroy_cq(fdq->cq));
 	if (fdq)
 		rte_free(fdq);
 	priv->flow_drop_queue = NULL;
@@ -2182,13 +2175,13 @@ priv_flow_delete_drop_queue(struct priv *priv)
 	if (!fdq)
 		return;
 	if (fdq->qp)
-		claim_zero(ibv_destroy_qp(fdq->qp));
+		claim_zero(mlx5_glue->destroy_qp(fdq->qp));
 	if (fdq->ind_table)
-		claim_zero(ibv_destroy_rwq_ind_table(fdq->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
 	if (fdq->wq)
-		claim_zero(ibv_destroy_wq(fdq->wq));
+		claim_zero(mlx5_glue->destroy_wq(fdq->wq));
 	if (fdq->cq)
-		claim_zero(ibv_destroy_cq(fdq->cq));
+		claim_zero(mlx5_glue->destroy_cq(fdq->cq));
 	rte_free(fdq);
 	priv->flow_drop_queue = NULL;
 }
@@ -2212,7 +2205,7 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
 		if (flow->drop) {
 			if (!flow->frxq[HASH_RXQ_ETH].ibv_flow)
 				continue;
-			claim_zero(ibv_destroy_flow
+			claim_zero(mlx5_glue->destroy_flow
 				   (flow->frxq[HASH_RXQ_ETH].ibv_flow));
 			flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
 			/* Next flow. */
@@ -2233,7 +2226,8 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
 		for (i = 0; i != hash_rxq_init_n; ++i) {
 			if (!flow->frxq[i].ibv_flow)
 				continue;
-			claim_zero(ibv_destroy_flow(flow->frxq[i].ibv_flow));
+			claim_zero(mlx5_glue->destroy_flow
+				   (flow->frxq[i].ibv_flow));
 			flow->frxq[i].ibv_flow = NULL;
 			mlx5_priv_hrxq_release(priv, flow->frxq[i].hrxq);
 			flow->frxq[i].hrxq = NULL;
@@ -2263,7 +2257,7 @@ priv_flow_start(struct priv *priv, struct mlx5_flows *list)
 
 		if (flow->drop) {
 			flow->frxq[HASH_RXQ_ETH].ibv_flow =
-				ibv_create_flow
+				mlx5_glue->create_flow
 				(priv->flow_drop_queue->qp,
 				 flow->frxq[HASH_RXQ_ETH].ibv_attr);
 			if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
@@ -2301,8 +2295,8 @@ priv_flow_start(struct priv *priv, struct mlx5_flows *list)
 			}
 flow_create:
 			flow->frxq[i].ibv_flow =
-				ibv_create_flow(flow->frxq[i].hrxq->qp,
-						flow->frxq[i].ibv_attr);
+				mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
+						       flow->frxq[i].ibv_attr);
 			if (!flow->frxq[i].ibv_flow) {
 				DEBUG("Flow %p cannot be applied",
 				      (void *)flow);
@@ -2509,7 +2503,7 @@ priv_flow_query_count(struct ibv_counter_set *cs,
 		.out = counters,
 		.outlen = 2 * sizeof(uint64_t),
 	};
-	int res = ibv_query_counter_set(&query_cs_attr, &query_out);
+	int res = mlx5_glue->query_counter_set(&query_cs_attr, &query_out);
 
 	if (res) {
 		rte_flow_error_set(error, -res,
diff --git a/drivers/net/mlx5/mlx5_glue.c b/drivers/net/mlx5/mlx5_glue.c
new file mode 100644
index 000000000..8f500be6e
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_glue.c
@@ -0,0 +1,352 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox Technologies, Ltd.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
+
+static int
+mlx5_glue_fork_init(void)
+{
+	return ibv_fork_init();
+}
+
+static struct ibv_pd *
+mlx5_glue_alloc_pd(struct ibv_context *context)
+{
+	return ibv_alloc_pd(context);
+}
+
+static int
+mlx5_glue_dealloc_pd(struct ibv_pd *pd)
+{
+	return ibv_dealloc_pd(pd);
+}
+
+static struct ibv_device **
+mlx5_glue_get_device_list(int *num_devices)
+{
+	return ibv_get_device_list(num_devices);
+}
+
+static void
+mlx5_glue_free_device_list(struct ibv_device **list)
+{
+	ibv_free_device_list(list);
+}
+
+static struct ibv_context *
+mlx5_glue_open_device(struct ibv_device *device)
+{
+	return ibv_open_device(device);
+}
+
+static int
+mlx5_glue_close_device(struct ibv_context *context)
+{
+	return ibv_close_device(context);
+}
+
+static int
+mlx5_glue_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context, device_attr);
+}
+
+static int
+mlx5_glue_query_device_ex(struct ibv_context *context,
+			  const struct ibv_query_device_ex_input *input,
+			  struct ibv_device_attr_ex *attr)
+{
+	return ibv_query_device_ex(context, input, attr);
+}
+
+static int
+mlx5_glue_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context, port_num, port_attr);
+}
+
+static struct ibv_comp_channel *
+mlx5_glue_create_comp_channel(struct ibv_context *context)
+{
+	return ibv_create_comp_channel(context);
+}
+
+static int
+mlx5_glue_destroy_comp_channel(struct ibv_comp_channel *channel)
+{
+	return ibv_destroy_comp_channel(channel);
+}
+
+static struct ibv_cq *
+mlx5_glue_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+		    struct ibv_comp_channel *channel, int comp_vector)
+{
+	return ibv_create_cq(context, cqe, cq_context, channel, comp_vector);
+}
+
+static int
+mlx5_glue_destroy_cq(struct ibv_cq *cq)
+{
+	return ibv_destroy_cq(cq);
+}
+
+static int
+mlx5_glue_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq,
+		       void **cq_context)
+{
+	return ibv_get_cq_event(channel, cq, cq_context);
+}
+
+static void
+mlx5_glue_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq, nevents);
+}
+
+static struct ibv_rwq_ind_table *
+mlx5_glue_create_rwq_ind_table(struct ibv_context *context,
+			       struct ibv_rwq_ind_table_init_attr *init_attr)
+{
+	return ibv_create_rwq_ind_table(context, init_attr);
+}
+
+static int
+mlx5_glue_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table)
+{
+	return ibv_destroy_rwq_ind_table(rwq_ind_table);
+}
+
+static struct ibv_wq *
+mlx5_glue_create_wq(struct ibv_context *context,
+		    struct ibv_wq_init_attr *wq_init_attr)
+{
+	return ibv_create_wq(context, wq_init_attr);
+}
+
+static int
+mlx5_glue_destroy_wq(struct ibv_wq *wq)
+{
+	return ibv_destroy_wq(wq);
+}
+static int
+mlx5_glue_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr)
+{
+	return ibv_modify_wq(wq, wq_attr);
+}
+
+static struct ibv_flow *
+mlx5_glue_create_flow(struct ibv_qp *qp, struct ibv_flow_attr *flow)
+{
+	return ibv_create_flow(qp, flow);
+}
+
+static int
+mlx5_glue_destroy_flow(struct ibv_flow *flow_id)
+{
+	return ibv_destroy_flow(flow_id);
+}
+
+static struct ibv_qp *
+mlx5_glue_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *qp_init_attr)
+{
+	return ibv_create_qp(pd, qp_init_attr);
+}
+
+static struct ibv_qp *
+mlx5_glue_create_qp_ex(struct ibv_context *context,
+		       struct ibv_qp_init_attr_ex *qp_init_attr_ex)
+{
+	return ibv_create_qp_ex(context, qp_init_attr_ex);
+}
+
+static int
+mlx5_glue_destroy_qp(struct ibv_qp *qp)
+{
+	return ibv_destroy_qp(qp);
+}
+
+static int
+mlx5_glue_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, int attr_mask)
+{
+	return ibv_modify_qp(qp, attr, attr_mask);
+}
+
+static struct ibv_mr *
+mlx5_glue_reg_mr(struct ibv_pd *pd, void *addr, size_t length, int access)
+{
+	return ibv_reg_mr(pd, addr, length, access);
+}
+
+static int
+mlx5_glue_dereg_mr(struct ibv_mr *mr)
+{
+	return ibv_dereg_mr(mr);
+}
+
+static struct ibv_counter_set *
+mlx5_glue_create_counter_set(struct ibv_context *context,
+			     struct ibv_counter_set_init_attr *init_attr)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)context;
+	(void)init_attr;
+	return NULL;
+#else
+	return ibv_create_counter_set(context, init_attr);
+#endif
+}
+
+static int
+mlx5_glue_destroy_counter_set(struct ibv_counter_set *cs)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)cs;
+	return ENOTSUP;
+#else
+	return ibv_destroy_counter_set(cs);
+#endif
+}
+
+static int
+mlx5_glue_describe_counter_set(struct ibv_context *context,
+			       uint16_t counter_set_id,
+			       struct ibv_counter_set_description *cs_desc)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)context;
+	(void)counter_set_id;
+	(void)cs_desc;
+	return ENOTSUP;
+#else
+	return ibv_describe_counter_set(context, counter_set_id, cs_desc);
+#endif
+}
+
+static int
+mlx5_glue_query_counter_set(struct ibv_query_counter_set_attr *query_attr,
+			    struct ibv_counter_set_data *cs_data)
+{
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+	(void)query_attr;
+	(void)cs_data;
+	return ENOTSUP;
+#else
+	return ibv_query_counter_set(query_attr, cs_data);
+#endif
+}
+
+static void
+mlx5_glue_ack_async_event(struct ibv_async_event *event)
+{
+	ibv_ack_async_event(event);
+}
+
+static int
+mlx5_glue_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
+{
+	return ibv_get_async_event(context, event);
+}
+
+static const char *
+mlx5_glue_port_state_str(enum ibv_port_state port_state)
+{
+	return ibv_port_state_str(port_state);
+}
+
+static struct ibv_cq *
+mlx5_glue_cq_ex_to_cq(struct ibv_cq_ex *cq)
+{
+	return ibv_cq_ex_to_cq(cq);
+}
+
+static struct ibv_cq_ex *
+mlx5_glue_dv_create_cq(struct ibv_context *context,
+		       struct ibv_cq_init_attr_ex *cq_attr,
+		       struct mlx5dv_cq_init_attr *mlx5_cq_attr)
+{
+	return mlx5dv_create_cq(context, cq_attr, mlx5_cq_attr);
+}
+
+static int
+mlx5_glue_dv_query_device(struct ibv_context *ctx,
+			  struct mlx5dv_context *attrs_out)
+{
+	return mlx5dv_query_device(ctx, attrs_out);
+}
+
+static int
+mlx5_glue_dv_set_context_attr(struct ibv_context *ibv_ctx,
+			      enum mlx5dv_set_ctx_attr_type type, void *attr)
+{
+	return mlx5dv_set_context_attr(ibv_ctx, type, attr);
+}
+
+static int
+mlx5_glue_dv_init_obj(struct mlx5dv_obj *obj, uint64_t obj_type)
+{
+	return mlx5dv_init_obj(obj, obj_type);
+}
+
+const struct mlx5_glue *mlx5_glue = &(const struct mlx5_glue){
+	.fork_init = mlx5_glue_fork_init,
+	.alloc_pd = mlx5_glue_alloc_pd,
+	.dealloc_pd = mlx5_glue_dealloc_pd,
+	.get_device_list = mlx5_glue_get_device_list,
+	.free_device_list = mlx5_glue_free_device_list,
+	.open_device = mlx5_glue_open_device,
+	.close_device = mlx5_glue_close_device,
+	.query_device = mlx5_glue_query_device,
+	.query_device_ex = mlx5_glue_query_device_ex,
+	.query_port = mlx5_glue_query_port,
+	.create_comp_channel = mlx5_glue_create_comp_channel,
+	.destroy_comp_channel = mlx5_glue_destroy_comp_channel,
+	.create_cq = mlx5_glue_create_cq,
+	.destroy_cq = mlx5_glue_destroy_cq,
+	.get_cq_event = mlx5_glue_get_cq_event,
+	.ack_cq_events = mlx5_glue_ack_cq_events,
+	.create_rwq_ind_table = mlx5_glue_create_rwq_ind_table,
+	.destroy_rwq_ind_table = mlx5_glue_destroy_rwq_ind_table,
+	.create_wq = mlx5_glue_create_wq,
+	.destroy_wq = mlx5_glue_destroy_wq,
+	.modify_wq = mlx5_glue_modify_wq,
+	.create_flow = mlx5_glue_create_flow,
+	.destroy_flow = mlx5_glue_destroy_flow,
+	.create_qp = mlx5_glue_create_qp,
+	.create_qp_ex = mlx5_glue_create_qp_ex,
+	.destroy_qp = mlx5_glue_destroy_qp,
+	.modify_qp = mlx5_glue_modify_qp,
+	.reg_mr = mlx5_glue_reg_mr,
+	.dereg_mr = mlx5_glue_dereg_mr,
+	.create_counter_set = mlx5_glue_create_counter_set,
+	.destroy_counter_set = mlx5_glue_destroy_counter_set,
+	.describe_counter_set = mlx5_glue_describe_counter_set,
+	.query_counter_set = mlx5_glue_query_counter_set,
+	.ack_async_event = mlx5_glue_ack_async_event,
+	.get_async_event = mlx5_glue_get_async_event,
+	.port_state_str = mlx5_glue_port_state_str,
+	.cq_ex_to_cq = mlx5_glue_cq_ex_to_cq,
+	.dv_create_cq = mlx5_glue_dv_create_cq,
+	.dv_query_device = mlx5_glue_dv_query_device,
+	.dv_set_context_attr = mlx5_glue_dv_set_context_attr,
+	.dv_init_obj = mlx5_glue_dv_init_obj,
+};
diff --git a/drivers/net/mlx5/mlx5_glue.h b/drivers/net/mlx5/mlx5_glue.h
new file mode 100644
index 000000000..6afb629ff
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_glue.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 6WIND S.A.
+ * Copyright 2018 Mellanox Technologies, Ltd.
+ */
+
+#ifndef MLX5_GLUE_H_
+#define MLX5_GLUE_H_
+
+#include <stdint.h>
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+struct ibv_counter_set;
+struct ibv_counter_set_data;
+struct ibv_counter_set_description;
+struct ibv_counter_set_init_attr;
+struct ibv_query_counter_set_attr;
+#endif
+
+struct mlx5_glue {
+	int (*fork_init)(void);
+	struct ibv_pd *(*alloc_pd)(struct ibv_context *context);
+	int (*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_device **(*get_device_list)(int *num_devices);
+	void (*free_device_list)(struct ibv_device **list);
+	struct ibv_context *(*open_device)(struct ibv_device *device);
+	int (*close_device)(struct ibv_context *context);
+	int (*query_device)(struct ibv_context *context,
+			    struct ibv_device_attr *device_attr);
+	int (*query_device_ex)(struct ibv_context *context,
+			       const struct ibv_query_device_ex_input *input,
+			       struct ibv_device_attr_ex *attr);
+	int (*query_port)(struct ibv_context *context, uint8_t port_num,
+			  struct ibv_port_attr *port_attr);
+	struct ibv_comp_channel *(*create_comp_channel)
+		(struct ibv_context *context);
+	int (*destroy_comp_channel)(struct ibv_comp_channel *channel);
+	struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe,
+				    void *cq_context,
+				    struct ibv_comp_channel *channel,
+				    int comp_vector);
+	int (*destroy_cq)(struct ibv_cq *cq);
+	int (*get_cq_event)(struct ibv_comp_channel *channel,
+			    struct ibv_cq **cq, void **cq_context);
+	void (*ack_cq_events)(struct ibv_cq *cq, unsigned int nevents);
+	struct ibv_rwq_ind_table *(*create_rwq_ind_table)
+		(struct ibv_context *context,
+		 struct ibv_rwq_ind_table_init_attr *init_attr);
+	int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table);
+	struct ibv_wq *(*create_wq)(struct ibv_context *context,
+				    struct ibv_wq_init_attr *wq_init_attr);
+	int (*destroy_wq)(struct ibv_wq *wq);
+	int (*modify_wq)(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr);
+	struct ibv_flow *(*create_flow)(struct ibv_qp *qp,
+					struct ibv_flow_attr *flow);
+	int (*destroy_flow)(struct ibv_flow *flow_id);
+	struct ibv_qp *(*create_qp)(struct ibv_pd *pd,
+				    struct ibv_qp_init_attr *qp_init_attr);
+	struct ibv_qp *(*create_qp_ex)
+		(struct ibv_context *context,
+		 struct ibv_qp_init_attr_ex *qp_init_attr_ex);
+	int (*destroy_qp)(struct ibv_qp *qp);
+	int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+			 int attr_mask);
+	struct ibv_mr *(*reg_mr)(struct ibv_pd *pd, void *addr,
+				 size_t length, int access);
+	int (*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_counter_set *(*create_counter_set)
+		(struct ibv_context *context,
+		 struct ibv_counter_set_init_attr *init_attr);
+	int (*destroy_counter_set)(struct ibv_counter_set *cs);
+	int (*describe_counter_set)
+		(struct ibv_context *context,
+		 uint16_t counter_set_id,
+		 struct ibv_counter_set_description *cs_desc);
+	int (*query_counter_set)(struct ibv_query_counter_set_attr *query_attr,
+				 struct ibv_counter_set_data *cs_data);
+	void (*ack_async_event)(struct ibv_async_event *event);
+	int (*get_async_event)(struct ibv_context *context,
+			       struct ibv_async_event *event);
+	const char *(*port_state_str)(enum ibv_port_state port_state);
+	struct ibv_cq *(*cq_ex_to_cq)(struct ibv_cq_ex *cq);
+	struct ibv_cq_ex *(*dv_create_cq)
+		(struct ibv_context *context,
+		 struct ibv_cq_init_attr_ex *cq_attr,
+		 struct mlx5dv_cq_init_attr *mlx5_cq_attr);
+	int (*dv_query_device)(struct ibv_context *ctx_in,
+			       struct mlx5dv_context *attrs_out);
+	int (*dv_set_context_attr)(struct ibv_context *ibv_ctx,
+				   enum mlx5dv_set_ctx_attr_type type,
+				   void *attr);
+	int (*dv_init_obj)(struct mlx5dv_obj *obj, uint64_t obj_type);
+};
+
+const struct mlx5_glue *mlx5_glue;
+
+#endif /* MLX5_GLUE_H_ */
diff --git a/drivers/net/mlx5/mlx5_mr.c b/drivers/net/mlx5/mlx5_mr.c
index 33d037d28..28769d386 100644
--- a/drivers/net/mlx5/mlx5_mr.c
+++ b/drivers/net/mlx5/mlx5_mr.c
@@ -46,6 +46,7 @@
 
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
+#include "mlx5_glue.h"
 
 struct mlx5_check_mempool_data {
 	int ret;
@@ -315,8 +316,8 @@ priv_mr_new(struct priv *priv, struct rte_mempool *mp)
 	DEBUG("mempool %p using start=%p end=%p size=%zu for MR",
 	      (void *)mp, (void *)start, (void *)end,
 	      (size_t)(end - start));
-	mr->mr = ibv_reg_mr(priv->pd, (void *)start, end - start,
-			    IBV_ACCESS_LOCAL_WRITE);
+	mr->mr = mlx5_glue->reg_mr(priv->pd, (void *)start, end - start,
+				   IBV_ACCESS_LOCAL_WRITE);
 	mr->mp = mp;
 	mr->lkey = rte_cpu_to_be_32(mr->mr->lkey);
 	rte_atomic32_inc(&mr->refcnt);
@@ -372,7 +373,7 @@ priv_mr_release(struct priv *priv, struct mlx5_mr *mr)
 	DEBUG("Memory Region %p refcnt: %d",
 	      (void *)mr, rte_atomic32_read(&mr->refcnt));
 	if (rte_atomic32_dec_and_test(&mr->refcnt)) {
-		claim_zero(ibv_dereg_mr(mr->mr));
+		claim_zero(mlx5_glue->dereg_mr(mr->mr));
 		LIST_REMOVE(mr, next);
 		rte_free(mr);
 		return 0;
diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c
index 3c716b960..c7b884ab5 100644
--- a/drivers/net/mlx5/mlx5_rxq.c
+++ b/drivers/net/mlx5/mlx5_rxq.c
@@ -63,6 +63,7 @@
 #include "mlx5_utils.h"
 #include "mlx5_autoconf.h"
 #include "mlx5_defs.h"
+#include "mlx5_glue.h"
 
 /* Default RSS hash key also used for ConnectX-3. */
 uint8_t rss_hash_default_key[] = {
@@ -601,13 +602,13 @@ mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id)
 		ret = EINVAL;
 		goto exit;
 	}
-	ret = ibv_get_cq_event(rxq_ibv->channel, &ev_cq, &ev_ctx);
+	ret = mlx5_glue->get_cq_event(rxq_ibv->channel, &ev_cq, &ev_ctx);
 	if (ret || ev_cq != rxq_ibv->cq) {
 		ret = EINVAL;
 		goto exit;
 	}
 	rxq_data->cq_arm_sn++;
-	ibv_ack_cq_events(rxq_ibv->cq, 1);
+	mlx5_glue->ack_cq_events(rxq_ibv->cq, 1);
 exit:
 	if (rxq_ibv)
 		mlx5_priv_rxq_ibv_release(priv, rxq_ibv);
@@ -675,7 +676,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		}
 	}
 	if (rxq_ctrl->irq) {
-		tmpl->channel = ibv_create_comp_channel(priv->ctx);
+		tmpl->channel = mlx5_glue->create_comp_channel(priv->ctx);
 		if (!tmpl->channel) {
 			ERROR("%p: Comp Channel creation failure",
 			      (void *)rxq_ctrl);
@@ -703,8 +704,9 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	} else if (config->cqe_comp && rxq_data->hw_timestamp) {
 		DEBUG("Rx CQE compression is disabled for HW timestamp");
 	}
-	tmpl->cq = ibv_cq_ex_to_cq(mlx5dv_create_cq(priv->ctx, &attr.cq.ibv,
-						    &attr.cq.mlx5));
+	tmpl->cq = mlx5_glue->cq_ex_to_cq
+		(mlx5_glue->dv_create_cq(priv->ctx, &attr.cq.ibv,
+					 &attr.cq.mlx5));
 	if (tmpl->cq == NULL) {
 		ERROR("%p: CQ creation failure", (void *)rxq_ctrl);
 		goto error;
@@ -740,7 +742,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		attr.wq.comp_mask |= IBV_WQ_INIT_ATTR_FLAGS;
 	}
 #endif
-	tmpl->wq = ibv_create_wq(priv->ctx, &attr.wq);
+	tmpl->wq = mlx5_glue->create_wq(priv->ctx, &attr.wq);
 	if (tmpl->wq == NULL) {
 		ERROR("%p: WQ creation failure", (void *)rxq_ctrl);
 		goto error;
@@ -764,7 +766,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 		.attr_mask = IBV_WQ_ATTR_STATE,
 		.wq_state = IBV_WQS_RDY,
 	};
-	ret = ibv_modify_wq(tmpl->wq, &mod);
+	ret = mlx5_glue->modify_wq(tmpl->wq, &mod);
 	if (ret) {
 		ERROR("%p: WQ state to IBV_WQS_RDY failed",
 		      (void *)rxq_ctrl);
@@ -774,7 +776,7 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	obj.cq.out = &cq_info;
 	obj.rwq.in = tmpl->wq;
 	obj.rwq.out = &rwq;
-	ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_RWQ);
+	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_RWQ);
 	if (ret != 0)
 		goto error;
 	if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
@@ -824,11 +826,11 @@ mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)
 	return tmpl;
 error:
 	if (tmpl->wq)
-		claim_zero(ibv_destroy_wq(tmpl->wq));
+		claim_zero(mlx5_glue->destroy_wq(tmpl->wq));
 	if (tmpl->cq)
-		claim_zero(ibv_destroy_cq(tmpl->cq));
+		claim_zero(mlx5_glue->destroy_cq(tmpl->cq));
 	if (tmpl->channel)
-		claim_zero(ibv_destroy_comp_channel(tmpl->channel));
+		claim_zero(mlx5_glue->destroy_comp_channel(tmpl->channel));
 	if (tmpl->mr)
 		priv_mr_release(priv, tmpl->mr);
 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
@@ -894,10 +896,11 @@ mlx5_priv_rxq_ibv_release(struct priv *priv, struct mlx5_rxq_ibv *rxq_ibv)
 	      (void *)rxq_ibv, rte_atomic32_read(&rxq_ibv->refcnt));
 	if (rte_atomic32_dec_and_test(&rxq_ibv->refcnt)) {
 		rxq_free_elts(rxq_ibv->rxq_ctrl);
-		claim_zero(ibv_destroy_wq(rxq_ibv->wq));
-		claim_zero(ibv_destroy_cq(rxq_ibv->cq));
+		claim_zero(mlx5_glue->destroy_wq(rxq_ibv->wq));
+		claim_zero(mlx5_glue->destroy_cq(rxq_ibv->cq));
 		if (rxq_ibv->channel)
-			claim_zero(ibv_destroy_comp_channel(rxq_ibv->channel));
+			claim_zero(mlx5_glue->destroy_comp_channel
+				   (rxq_ibv->channel));
 		LIST_REMOVE(rxq_ibv, next);
 		rte_free(rxq_ibv);
 		return 0;
@@ -1225,13 +1228,13 @@ mlx5_priv_ind_table_ibv_new(struct priv *priv, uint16_t queues[],
 	/* Finalise indirection table. */
 	for (j = 0; i != (unsigned int)(1 << wq_n); ++i, ++j)
 		wq[i] = wq[j];
-	ind_tbl->ind_table = ibv_create_rwq_ind_table(
-		priv->ctx,
-		&(struct ibv_rwq_ind_table_init_attr){
+	ind_tbl->ind_table = mlx5_glue->create_rwq_ind_table
+		(priv->ctx,
+		 &(struct ibv_rwq_ind_table_init_attr){
 			.log_ind_tbl_size = wq_n,
 			.ind_tbl = wq,
 			.comp_mask = 0,
-		});
+		 });
 	if (!ind_tbl->ind_table)
 		goto error;
 	rte_atomic32_inc(&ind_tbl->refcnt);
@@ -1303,7 +1306,8 @@ mlx5_priv_ind_table_ibv_release(struct priv *priv,
 	DEBUG("%p: Indirection table %p: refcnt %d", (void *)priv,
 	      (void *)ind_tbl, rte_atomic32_read(&ind_tbl->refcnt));
 	if (rte_atomic32_dec_and_test(&ind_tbl->refcnt))
-		claim_zero(ibv_destroy_rwq_ind_table(ind_tbl->ind_table));
+		claim_zero(mlx5_glue->destroy_rwq_ind_table
+			   (ind_tbl->ind_table));
 	for (i = 0; i != ind_tbl->queues_n; ++i)
 		claim_nonzero(mlx5_priv_rxq_release(priv, ind_tbl->queues[i]));
 	if (!rte_atomic32_read(&ind_tbl->refcnt)) {
@@ -1370,9 +1374,9 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 		ind_tbl = mlx5_priv_ind_table_ibv_new(priv, queues, queues_n);
 	if (!ind_tbl)
 		return NULL;
-	qp = ibv_create_qp_ex(
-		priv->ctx,
-		&(struct ibv_qp_init_attr_ex){
+	qp = mlx5_glue->create_qp_ex
+		(priv->ctx,
+		 &(struct ibv_qp_init_attr_ex){
 			.qp_type = IBV_QPT_RAW_PACKET,
 			.comp_mask =
 				IBV_QP_INIT_ATTR_PD |
@@ -1386,7 +1390,7 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 			},
 			.rwq_ind_tbl = ind_tbl->ind_table,
 			.pd = priv->pd,
-		});
+		 });
 	if (!qp)
 		goto error;
 	hrxq = rte_calloc(__func__, 1, sizeof(*hrxq) + rss_key_len, 0);
@@ -1405,7 +1409,7 @@ mlx5_priv_hrxq_new(struct priv *priv, uint8_t *rss_key, uint8_t rss_key_len,
 error:
 	mlx5_priv_ind_table_ibv_release(priv, ind_tbl);
 	if (qp)
-		claim_zero(ibv_destroy_qp(qp));
+		claim_zero(mlx5_glue->destroy_qp(qp));
 	return NULL;
 }
 
@@ -1473,7 +1477,7 @@ mlx5_priv_hrxq_release(struct priv *priv, struct mlx5_hrxq *hrxq)
 	DEBUG("%p: Hash Rx queue %p: refcnt %d", (void *)priv,
 	      (void *)hrxq, rte_atomic32_read(&hrxq->refcnt));
 	if (rte_atomic32_dec_and_test(&hrxq->refcnt)) {
-		claim_zero(ibv_destroy_qp(hrxq->qp));
+		claim_zero(mlx5_glue->destroy_qp(hrxq->qp));
 		mlx5_priv_ind_table_ibv_release(priv, hrxq->ind_table);
 		LIST_REMOVE(hrxq, next);
 		rte_free(hrxq);
diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c
index 65086d36f..bdaca5a00 100644
--- a/drivers/net/mlx5/mlx5_txq.c
+++ b/drivers/net/mlx5/mlx5_txq.c
@@ -59,6 +59,7 @@
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
 #include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
 
 /**
  * Allocate TX queue elements.
@@ -432,7 +433,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		((desc / MLX5_TX_COMP_THRESH) - 1) : 1;
 	if (is_empw_burst_func(tx_pkt_burst))
 		cqe_n += MLX5_TX_COMP_THRESH_INLINE_DIV;
-	tmpl.cq = ibv_create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
+	tmpl.cq = mlx5_glue->create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
 	if (tmpl.cq == NULL) {
 		ERROR("%p: CQ creation failure", (void *)txq_ctrl);
 		goto error;
@@ -473,7 +474,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		attr.init.max_tso_header = txq_ctrl->max_tso_header;
 		attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
 	}
-	tmpl.qp = ibv_create_qp_ex(priv->ctx, &attr.init);
+	tmpl.qp = mlx5_glue->create_qp_ex(priv->ctx, &attr.init);
 	if (tmpl.qp == NULL) {
 		ERROR("%p: QP creation failure", (void *)txq_ctrl);
 		goto error;
@@ -484,7 +485,8 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 		/* Primary port number. */
 		.port_num = priv->port
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, (IBV_QP_STATE | IBV_QP_PORT));
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod,
+				   (IBV_QP_STATE | IBV_QP_PORT));
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_INIT failed", (void *)txq_ctrl);
 		goto error;
@@ -492,13 +494,13 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	attr.mod = (struct ibv_qp_attr){
 		.qp_state = IBV_QPS_RTR
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_RTR failed", (void *)txq_ctrl);
 		goto error;
 	}
 	attr.mod.qp_state = IBV_QPS_RTS;
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		ERROR("%p: QP state to IBV_QPS_RTS failed", (void *)txq_ctrl);
 		goto error;
@@ -513,7 +515,7 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	obj.cq.out = &cq_info;
 	obj.qp.in = tmpl.qp;
 	obj.qp.out = &qp;
-	ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
+	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
 	if (ret != 0)
 		goto error;
 	if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
@@ -553,9 +555,9 @@ mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
 	return txq_ibv;
 error:
 	if (tmpl.cq)
-		claim_zero(ibv_destroy_cq(tmpl.cq));
+		claim_zero(mlx5_glue->destroy_cq(tmpl.cq));
 	if (tmpl.qp)
-		claim_zero(ibv_destroy_qp(tmpl.qp));
+		claim_zero(mlx5_glue->destroy_qp(tmpl.qp));
 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
 	return NULL;
 }
@@ -609,8 +611,8 @@ mlx5_priv_txq_ibv_release(struct priv *priv, struct mlx5_txq_ibv *txq_ibv)
 	DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
 	      (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
 	if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
-		claim_zero(ibv_destroy_qp(txq_ibv->qp));
-		claim_zero(ibv_destroy_cq(txq_ibv->cq));
+		claim_zero(mlx5_glue->destroy_qp(txq_ibv->qp));
+		claim_zero(mlx5_glue->destroy_cq(txq_ibv->cq));
 		LIST_REMOVE(txq_ibv, next);
 		rte_free(txq_ibv);
 		return 0;
diff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c
index d51dbe941..f55e5e020 100644
--- a/drivers/net/mlx5/mlx5_vlan.c
+++ b/drivers/net/mlx5/mlx5_vlan.c
@@ -36,12 +36,23 @@
 #include <assert.h>
 #include <stdint.h>
 
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/mlx5dv.h>
+#include <infiniband/verbs.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
 #include <rte_ethdev_driver.h>
 #include <rte_common.h>
 
 #include "mlx5_utils.h"
 #include "mlx5.h"
 #include "mlx5_autoconf.h"
+#include "mlx5_glue.h"
 
 /**
  * DPDK callback to configure a VLAN filter.
@@ -138,7 +149,7 @@ priv_vlan_strip_queue_set(struct priv *priv, uint16_t idx, int on)
 		.flags = vlan_offloads,
 	};
 
-	err = ibv_modify_wq(rxq_ctrl->ibv->wq, &mod);
+	err = mlx5_glue->modify_wq(rxq_ctrl->ibv->wq, &mod);
 	if (err) {
 		ERROR("%p: failed to modified stripping mode: %s",
 		      (void *)priv, strerror(err));
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 4/4] net/mlx5: spawn rdma-core dependency plug-in
  2018-01-30 15:34     ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
                         ` (2 preceding siblings ...)
  2018-01-30 15:34       ` [PATCH v4 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
@ 2018-01-30 15:34       ` Adrien Mazarguil
  2018-01-31 10:13       ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Shahaf Shuler
  4 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-30 15:34 UTC (permalink / raw)
  To: Shahaf Shuler; +Cc: Nelio Laranjeiro, dev, Marcelo Ricardo Leitner

When mlx5 is not compiled directly as an independent shared object (e.g.
CONFIG_RTE_BUILD_SHARED_LIB not enabled for performance reasons), DPDK
applications inherit its dependencies on libibverbs and libmlx5 through
rte.app.mk.

This is an issue both when DPDK is delivered as a binary package (Linux
distributions) and for end users because rdma-core then propagates as a
mandatory dependency for everything.

Application writers relying on binary DPDK packages are not necessarily
aware of this fact and may end up delivering packages with broken
dependencies.

This patch therefore introduces an intermediate internal plug-in
hard-linked with rdma-core (to preserve symbol versioning) loaded by the
PMD through dlopen(), so that a missing rdma-core does not cause unresolved
symbols, allowing applications to start normally.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
---
 config/common_base        |  1 +
 doc/guides/nics/mlx5.rst  | 13 ++++++++++++
 drivers/net/mlx5/Makefile | 31 ++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5.c   | 48 ++++++++++++++++++++++++++++++++++++++++++
 mk/rte.app.mk             |  4 ++++
 5 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/config/common_base b/config/common_base
index 6df20be0e..b9b421db7 100644
--- a/config/common_base
+++ b/config/common_base
@@ -306,6 +306,7 @@ CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8
 #
 CONFIG_RTE_LIBRTE_MLX5_PMD=n
 CONFIG_RTE_LIBRTE_MLX5_DEBUG=n
+CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=n
 CONFIG_RTE_LIBRTE_MLX5_TX_MP_CACHE=8
 
 #
diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index 2e6d1e45a..a9e4bf51a 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -159,6 +159,19 @@ These options can be modified in the ``.config`` file.
 
   Toggle compilation of librte_pmd_mlx5 itself.
 
+- ``CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS`` (default **n**)
+
+  Build PMD with additional code to make it loadable without hard
+  dependencies on **libibverbs** nor **libmlx5**, which may not be installed
+  on the target system.
+
+  In this mode, their presence is still required for it to run properly,
+  however their absence won't prevent a DPDK application from starting (with
+  ``CONFIG_RTE_BUILD_SHARED_LIB`` disabled) and they won't show up as
+  missing with ``ldd(1)``.
+
+  This option has no performance impact.
+
 - ``CONFIG_RTE_LIBRTE_MLX5_DEBUG`` (default **n**)
 
   Toggle debugging code and stricter compilation flags. Enabling this option
diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index bdec30692..4b20d718b 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -33,9 +33,13 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 # Library name.
 LIB = librte_pmd_mlx5.a
+LIB_GLUE = librte_pmd_mlx5_glue.so
 
 # Sources.
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5.c
+ifneq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
+endif
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rxq.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_txq.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rxtx.c
@@ -53,7 +57,10 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c
-SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_glue.c
+
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+INSTALL-$(CONFIG_RTE_LIBRTE_MLX5_PMD)-lib += $(LIB_GLUE)
+endif
 
 # Basic CFLAGS.
 CFLAGS += -O3
@@ -65,7 +72,13 @@ CFLAGS += -D_DEFAULT_SOURCE
 CFLAGS += -D_XOPEN_SOURCE=600
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -Wno-strict-prototypes
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+CFLAGS += -DMLX5_GLUE='"$(LIB_GLUE)"'
+CFLAGS_mlx5_glue.o += -fPIC
+LDLIBS += -ldl
+else
 LDLIBS += -libverbs -lmlx5
+endif
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
@@ -158,7 +171,23 @@ mlx5_autoconf.h: mlx5_autoconf.h.new
 
 $(SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD):.c=.o): mlx5_autoconf.h
 
+# Generate dependency plug-in for rdma-core when the PMD must not be linked
+# directly, so that applications do not inherit this dependency.
+
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+
+$(LIB): $(LIB_GLUE)
+
+$(LIB_GLUE): mlx5_glue.o
+	$Q $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) \
+		-s -shared -o $@ $< -libverbs -lmlx5
+
+mlx5_glue.o: mlx5_autoconf.h
+
+endif
+
 clean_mlx5: FORCE
 	$Q rm -f -- mlx5_autoconf.h mlx5_autoconf.h.new
+	$Q rm -f -- mlx5_glue.o $(LIB_GLUE)
 
 clean: clean_mlx5
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index b911d0ad4..466a8b0a2 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -35,6 +35,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>
+#include <dlfcn.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -57,6 +58,7 @@
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
 #include <rte_common.h>
+#include <rte_config.h>
 #include <rte_eal_memconfig.h>
 #include <rte_kvargs.h>
 
@@ -1075,6 +1077,47 @@ static struct rte_pci_driver mlx5_driver = {
 	.drv_flags = RTE_PCI_DRV_INTR_LSC | RTE_PCI_DRV_INTR_RMV,
 };
 
+#ifdef RTE_LIBRTE_MLX5_DLOPEN_DEPS
+
+/**
+ * Initialization routine for run-time dependency on rdma-core.
+ */
+static int
+mlx5_glue_init(void)
+{
+	void *handle = NULL;
+	void **sym;
+	const char *dlmsg;
+
+	handle = dlopen(MLX5_GLUE, RTLD_LAZY);
+	if (!handle) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot load glue library: %s", dlmsg);
+		goto glue_error;
+	}
+	sym = dlsym(handle, "mlx5_glue");
+	if (!sym || !*sym) {
+		rte_errno = EINVAL;
+		dlmsg = dlerror();
+		if (dlmsg)
+			ERROR("cannot resolve glue symbol: %s", dlmsg);
+		goto glue_error;
+	}
+	mlx5_glue = *sym;
+	return 0;
+glue_error:
+	if (handle)
+		dlclose(handle);
+	ERROR("cannot initialize PMD due to missing run-time"
+	      " dependency on rdma-core libraries (libibverbs,"
+	      " libmlx5)");
+	return -rte_errno;
+}
+
+#endif
+
 /**
  * Driver initialization routine.
  */
@@ -1094,6 +1137,11 @@ rte_mlx5_pmd_init(void)
 	/* Match the size of Rx completion entry to the size of a cacheline. */
 	if (RTE_CACHE_LINE_SIZE == 128)
 		setenv("MLX5_CQE_SIZE", "128", 0);
+#ifdef RTE_LIBRTE_MLX5_DLOPEN_DEPS
+	if (mlx5_glue_init())
+		return;
+	assert(mlx5_glue);
+#endif
 	mlx5_glue->fork_init();
 	rte_pci_register(&mlx5_driver);
 }
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index fdbe36630..88f626049 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -148,7 +148,11 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -ldl
 else
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs -lmlx4
 endif
+ifeq ($(CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS),y)
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -ldl
+else
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs -lmlx5
+endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v4 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-30 15:34       ` [PATCH v4 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-30 17:54         ` Marcelo Ricardo Leitner
  2018-01-30 18:32           ` Adrien Mazarguil
  0 siblings, 1 reply; 31+ messages in thread
From: Marcelo Ricardo Leitner @ 2018-01-30 17:54 UTC (permalink / raw)
  To: Adrien Mazarguil; +Cc: Shahaf Shuler, Nelio Laranjeiro, dev

On Tue, Jan 30, 2018 at 04:34:54PM +0100, Adrien Mazarguil wrote:
...
> +	handle = dlopen(MLX4_GLUE, RTLD_LAZY);
> +	if (!handle) {
> +		rte_errno = EINVAL;
> +		dlmsg = dlerror();
> +		if (dlmsg)
> +			ERROR("cannot load glue library: %s", dlmsg);
> +		goto glue_error;
> +	}
> +	sym = dlsym(handle, "mlx4_glue");
> +	if (!sym || !*sym) {
> +		rte_errno = EINVAL;
> +		dlmsg = dlerror();
> +		if (dlmsg)
> +			ERROR("cannot resolve glue symbol: %s", dlmsg);
> +		goto glue_error;
> +	}
> +	mlx4_glue = *sym;
> +	return 0;
> +glue_error:
> +	if (handle)
> +		dlclose(handle);
> +	ERROR("cannot initialize PMD due to missing run-time"
> +	      " dependency on rdma-core libraries (libibverbs,"
> +	      " libmlx4)");

Patches are mostly LGTM. The only concern left is if ERROR is the
appropriate log level here. I know it's a fatal error for Mellanox
cards, but Considering DPDK will load all drivers for probing the hw,
these messages will show up even when using other cards. So what about
switching to WARNING instead? Should be less confusing to the users
then.

  Marcelo

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v4 2/4] net/mlx4: spawn rdma-core dependency plug-in
  2018-01-30 17:54         ` Marcelo Ricardo Leitner
@ 2018-01-30 18:32           ` Adrien Mazarguil
  0 siblings, 0 replies; 31+ messages in thread
From: Adrien Mazarguil @ 2018-01-30 18:32 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner; +Cc: Shahaf Shuler, Nelio Laranjeiro, dev

On Tue, Jan 30, 2018 at 03:54:59PM -0200, Marcelo Ricardo Leitner wrote:
> On Tue, Jan 30, 2018 at 04:34:54PM +0100, Adrien Mazarguil wrote:
> ...
> > +	handle = dlopen(MLX4_GLUE, RTLD_LAZY);
> > +	if (!handle) {
> > +		rte_errno = EINVAL;
> > +		dlmsg = dlerror();
> > +		if (dlmsg)
> > +			ERROR("cannot load glue library: %s", dlmsg);
> > +		goto glue_error;
> > +	}
> > +	sym = dlsym(handle, "mlx4_glue");
> > +	if (!sym || !*sym) {
> > +		rte_errno = EINVAL;
> > +		dlmsg = dlerror();
> > +		if (dlmsg)
> > +			ERROR("cannot resolve glue symbol: %s", dlmsg);
> > +		goto glue_error;
> > +	}
> > +	mlx4_glue = *sym;
> > +	return 0;
> > +glue_error:
> > +	if (handle)
> > +		dlclose(handle);
> > +	ERROR("cannot initialize PMD due to missing run-time"
> > +	      " dependency on rdma-core libraries (libibverbs,"
> > +	      " libmlx4)");
> 
> Patches are mostly LGTM. The only concern left is if ERROR is the
> appropriate log level here. I know it's a fatal error for Mellanox
> cards, but Considering DPDK will load all drivers for probing the hw,
> these messages will show up even when using other cards. So what about
> switching to WARNING instead? Should be less confusing to the users
> then.

Right, this is a leftover from the orginal patch that bundled mlx4_glue.so
with the PMD. An error message should only be printed when dlsym() fails,
not dlopen().

Depending on whether this series gets applied in the meantime, I'll either
send a v5 update or a separate fix tomorrow.

-- 
Adrien Mazarguil
6WIND

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time
  2018-01-30 15:34     ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
                         ` (3 preceding siblings ...)
  2018-01-30 15:34       ` [PATCH v4 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
@ 2018-01-31 10:13       ` Shahaf Shuler
  4 siblings, 0 replies; 31+ messages in thread
From: Shahaf Shuler @ 2018-01-31 10:13 UTC (permalink / raw)
  To: Adrien Mazarguil; +Cc: Nélio Laranjeiro, dev, Marcelo Ricardo Leitner

Tuesday, January 30, 2018 5:35 PM, Adrien Mazarguil:
> Subject: [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time
> 
> A problem encountered with Mellanox PMDs and frequently reported by
> DPDK application developers and Linux distribution package maintainers is
> their dependency on rdma-core components, namely libibverbs, libmlx4, and
> libmlx5.
> 
> For best performance in applications, DPDK is normally built as a collection of
> library archives (.a files), whose external dependencies are inherited through
> rte.app.mk during link.
> 
> When these PMDs are built-in, any binary DPDK package, whether DPDK
> itself or derived applications, always have to pull rdma-core. This
> dependency is not obvious and may be missed during the packaging of any
> intermediate layer between DPDK itself and the end application.
> 
> While still required during compilation, this series trades this hard
> dependency for an optional one, dynamically loaded at run-time through
> dlopen().
> 
> It supersedes Shachar's previous work on the same topic [1] using a different
> approach in order to preserve symbol versioning and address the remaining
> issues.
> 

Series applied to next-net-mlx with the requested conversion from ERROR to WARN upon dlopen failure. Please check fix is OK. 
Thanks.

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2018-01-31 10:13 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-24 23:24 [PATCH v1 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
2018-01-24 23:25 ` [PATCH v1 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
2018-01-24 23:58   ` Stephen Hemminger
2018-01-25 11:31     ` Adrien Mazarguil
2018-01-24 23:25 ` [PATCH v1 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
2018-01-26 10:06   ` Thomas Monjalon
2018-01-24 23:25 ` [PATCH v1 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
2018-01-24 23:25 ` [PATCH v1 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
2018-01-26 14:18 ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
2018-01-26 14:18   ` [PATCH v2 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
2018-01-26 14:19   ` [PATCH v2 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
2018-01-27 15:03     ` Marcelo Ricardo Leitner
2018-01-28  9:04       ` Shahaf Shuler
2018-01-28 11:17         ` Marcelo Ricardo Leitner
2018-01-28 11:46           ` Shahaf Shuler
2018-01-26 14:19   ` [PATCH v2 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
2018-01-26 14:19   ` [PATCH v2 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
2018-01-26 15:58   ` [PATCH v2 0/4] net/mlx: make rdma-core optional at run-time Nélio Laranjeiro
2018-01-29 17:19   ` [PATCH v3 " Adrien Mazarguil
2018-01-29 17:19     ` [PATCH v3 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
2018-01-29 17:19     ` [PATCH v3 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
2018-01-29 17:19     ` [PATCH v3 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
2018-01-29 17:19     ` [PATCH v3 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
2018-01-30 15:34     ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Adrien Mazarguil
2018-01-30 15:34       ` [PATCH v4 1/4] net/mlx4: move rdma-core calls to separate file Adrien Mazarguil
2018-01-30 15:34       ` [PATCH v4 2/4] net/mlx4: spawn rdma-core dependency plug-in Adrien Mazarguil
2018-01-30 17:54         ` Marcelo Ricardo Leitner
2018-01-30 18:32           ` Adrien Mazarguil
2018-01-30 15:34       ` [PATCH v4 3/4] net/mlx5: move rdma-core calls to separate file Adrien Mazarguil
2018-01-30 15:34       ` [PATCH v4 4/4] net/mlx5: spawn rdma-core dependency plug-in Adrien Mazarguil
2018-01-31 10:13       ` [PATCH v4 0/4] net/mlx: make rdma-core optional at run-time Shahaf Shuler

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.