[openib-general] [RFT] [PATCH] Add ABI compatibility for apps linked against libibverbs 1.0

Roland Dreier rdreier at cisco.com
Tue Jan 23 16:56:04 PST 2007


Here is a patch that attempts to make it possible use libibverbs 1.1
(ie the libibverbs.git master branch) to run applications compiled and
linked against libibverbs 1.0.  I would appreciate it if people who
have such applications could test this out.

In particular, I would like to know the results of the following: 
 - build your application as normal against a libibverbs 1.0 tree
   (either from OFED <= 1.1, or the "stable" branch of libibverbs.git)
 - get the libibverbs.git tree:
     git clone git://git.kernel.org/pub/scm/libs/infiniband/libibverbs.git libibverbs.git
 - apply the patch below
     patch -p1 < [this email]
 - build and install the libibverbs.git tree
 - build and install the low-level driver(s) (libmthca, libipathverbs,
   libehca, etc) you want to test, using your libibverbs.git tree
 - run the binary of your application built against libibverbs 1.0
   with the library from your libibverbs.git build (LD_LIBRARY_PATH
   may be useful; please use ldd to make sure your application is
   really picking up the new libibverbs library rather than the old
   one, or else you're not really testing the ABI compatibility)
 - reply to this email and report bugs or (perhaps) success

I've tested the trivial examples in the libibverbs package
(ibv_xxx_pingpong tests, ibv_devinfo, etc) but I'm sure that someone
has an app using something not covered there...

Thanks!
  Roland

---

Add a compatibility layer that allows applications (but not low-level
drivers) linked against libibverbs 1.0 to work with libibverbs 1.1.
This is done by using Linux's versioned symbol linking support: the
native libibverbs entry points are given IBVERBS_1.1 versions, and
compatibility wrappers for entry points from libibverbs 1.0 are
created with an IBVERBS_1.0 version (to match what libibverbs 1.0
exported).

In essense these wrappers create compatible proxies for every
structure returned to the application (struct ibv_device, ibv_context,
ibv_pd, etc), and map between the proxy and the real object when the
application calls into libibverbs.  This code is mostly
straightforward, with a few complications in handling async events,
because the pointers in event structures must be translated back to
proxy structures when they are returned to the application.

There are a few further wrinkles because the calls to data path
functions (poll CQ, post send, etc) are actually inline functions that
call directly into the context ops, so the context ops proxy structure
must actually contain pointers to compatibility wrappers for these
functions as well.  This may have some performance impact but it seems
the overhead is unavoidable.

Signed-off-by: Roland Dreier <rolandd at cisco.com>
---
 Makefile.am        |    6 +-
 configure.in       |    8 +
 src/compat-1_0.c   |  876 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/device.c       |   28 +-
 src/ibverbs.h      |   14 +
 src/libibverbs.map |   23 +-
 src/verbs.c        |  106 ++++---
 7 files changed, 1001 insertions(+), 60 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 35f4468..4c7ce9b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,9 +8,9 @@ src_libibverbs_la_CFLAGS = $(AM_CFLAGS) -DIBV_CONFIG_DIR=\"$(sysconfdir)/libibve
 
 libibverbs_version_script = @LIBIBVERBS_VERSION_SCRIPT@
 
-src_libibverbs_la_SOURCES = src/cmd.c src/device.c src/init.c src/marshall.c \
-			    src/memory.c src/sysfs.c src/verbs.c
-src_libibverbs_la_LDFLAGS = -version-info 2 -export-dynamic \
+src_libibverbs_la_SOURCES = src/cmd.c src/compat-1_0.c src/device.c src/init.c \
+			    src/marshall.c src/memory.c src/sysfs.c src/verbs.c
+src_libibverbs_la_LDFLAGS = -version-info 1 -export-dynamic \
     $(libibverbs_version_script)
 src_libibverbs_la_DEPENDENCIES = $(srcdir)/src/libibverbs.map
 
diff --git a/configure.in b/configure.in
index d98867f..7e7d448 100644
--- a/configure.in
+++ b/configure.in
@@ -50,5 +50,13 @@ AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script,
     fi])
 AC_SUBST(LIBIBVERBS_VERSION_SCRIPT)
 
+AC_CACHE_CHECK(for .symver assembler support, ac_cv_asm_symver_support,
+    [AC_TRY_COMPILE(, [asm("symbol:\n.symverx symbol, api at ABI\n");],
+        ac_cv_asm_symver_support=yes,
+        ac_cv_asm_symver_support=no)])
+if test $ac_cv_asm_symver_support = yes; then
+    AC_DEFINE([HAVE_SYMVER_SUPPORT], 1, [assembler has .symver support])
+fi
+
 AC_CONFIG_FILES([Makefile libibverbs.spec])
 AC_OUTPUT
diff --git a/src/compat-1_0.c b/src/compat-1_0.c
new file mode 100644
index 0000000..bfbf6a9
--- /dev/null
+++ b/src/compat-1_0.c
@@ -0,0 +1,876 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <alloca.h>
+
+#include "ibverbs.h"
+
+struct ibv_pd_1_0 {
+	struct ibv_context_1_0 *context;
+	uint32_t		handle;
+
+	struct ibv_pd	       *real_pd;
+};
+
+struct ibv_mr_1_0 {
+	struct ibv_context_1_0 *context;
+	struct ibv_pd_1_0      *pd;
+	uint32_t		handle;
+	uint32_t		lkey;
+	uint32_t		rkey;
+
+	struct ibv_mr	       *real_mr;
+};
+
+struct ibv_srq_1_0 {
+	struct ibv_context_1_0 *context;
+	void		       *srq_context;
+	struct ibv_pd_1_0      *pd;
+	uint32_t		handle;
+
+	pthread_mutex_t		mutex;
+	pthread_cond_t		cond;
+	uint32_t		events_completed;
+
+	struct ibv_srq	       *real_srq;
+};
+
+struct ibv_qp_init_attr_1_0 {
+	void		       *qp_context;
+	struct ibv_cq_1_0      *send_cq;
+	struct ibv_cq_1_0      *recv_cq;
+	struct ibv_srq_1_0     *srq;
+	struct ibv_qp_cap	cap;
+	enum ibv_qp_type	qp_type;
+	int			sq_sig_all;
+};
+
+struct ibv_send_wr_1_0 {
+	struct ibv_send_wr_1_0 *next;
+	uint64_t		wr_id;
+	struct ibv_sge	       *sg_list;
+	int			num_sge;
+	enum ibv_wr_opcode	opcode;
+	enum ibv_send_flags	send_flags;
+	uint32_t		imm_data;	/* in network byte order */
+	union {
+		struct {
+			uint64_t	remote_addr;
+			uint32_t	rkey;
+		} rdma;
+		struct {
+			uint64_t	remote_addr;
+			uint64_t	compare_add;
+			uint64_t	swap;
+			uint32_t	rkey;
+		} atomic;
+		struct {
+			struct ibv_ah_1_0 *ah;
+			uint32_t	remote_qpn;
+			uint32_t	remote_qkey;
+		} ud;
+	} wr;
+};
+
+struct ibv_recv_wr_1_0 {
+	struct ibv_recv_wr_1_0 *next;
+	uint64_t		wr_id;
+	struct ibv_sge	       *sg_list;
+	int			num_sge;
+};
+
+struct ibv_qp_1_0 {
+	struct ibv_context_1_0 *context;
+	void		       *qp_context;
+	struct ibv_pd_1_0      *pd;
+	struct ibv_cq_1_0      *send_cq;
+	struct ibv_cq_1_0      *recv_cq;
+	struct ibv_srq_1_0     *srq;
+	uint32_t		handle;
+	uint32_t		qp_num;
+	enum ibv_qp_state       state;
+	enum ibv_qp_type	qp_type;
+
+	pthread_mutex_t		mutex;
+	pthread_cond_t		cond;
+	uint32_t		events_completed;
+
+	struct ibv_qp	       *real_qp;
+};
+
+struct ibv_cq_1_0 {
+	struct ibv_context_1_0 *context;
+	void		       *cq_context;
+	uint32_t		handle;
+	int			cqe;
+
+	pthread_mutex_t		mutex;
+	pthread_cond_t		cond;
+	uint32_t		comp_events_completed;
+	uint32_t		async_events_completed;
+
+	struct ibv_cq	       *real_cq;
+};
+
+struct ibv_ah_1_0 {
+	struct ibv_context_1_0 *context;
+	struct ibv_pd_1_0      *pd;
+	uint32_t		handle;
+
+	struct ibv_ah	       *real_ah;
+};
+
+struct ibv_device_1_0 {
+	void		       *obsolete_sysfs_dev;
+	void		       *obsolete_sysfs_ibdev;
+	struct ibv_device      *real_device; /* was obsolete driver member */
+	struct ibv_device_ops	ops;
+};
+
+struct ibv_context_ops_1_0 {
+	int			(*query_device)(struct ibv_context *context,
+					      struct ibv_device_attr *device_attr);
+	int			(*query_port)(struct ibv_context *context, uint8_t port_num,
+					      struct ibv_port_attr *port_attr);
+	struct ibv_pd *		(*alloc_pd)(struct ibv_context *context);
+	int			(*dealloc_pd)(struct ibv_pd *pd);
+	struct ibv_mr *		(*reg_mr)(struct ibv_pd *pd, void *addr, size_t length,
+					  enum ibv_access_flags access);
+	int			(*dereg_mr)(struct ibv_mr *mr);
+	struct ibv_cq *		(*create_cq)(struct ibv_context *context, int cqe,
+					     struct ibv_comp_channel *channel,
+					     int comp_vector);
+	int			(*poll_cq)(struct ibv_cq_1_0 *cq, int num_entries,
+					   struct ibv_wc *wc);
+	int			(*req_notify_cq)(struct ibv_cq_1_0 *cq,
+						 int solicited_only);
+	void			(*cq_event)(struct ibv_cq *cq);
+	int			(*resize_cq)(struct ibv_cq *cq, int cqe);
+	int			(*destroy_cq)(struct ibv_cq *cq);
+	struct ibv_srq *	(*create_srq)(struct ibv_pd *pd,
+					      struct ibv_srq_init_attr *srq_init_attr);
+	int			(*modify_srq)(struct ibv_srq *srq,
+					      struct ibv_srq_attr *srq_attr,
+					      enum ibv_srq_attr_mask srq_attr_mask);
+	int			(*query_srq)(struct ibv_srq *srq,
+					     struct ibv_srq_attr *srq_attr);
+	int			(*destroy_srq)(struct ibv_srq *srq);
+	int			(*post_srq_recv)(struct ibv_srq_1_0 *srq,
+						 struct ibv_recv_wr_1_0 *recv_wr,
+						 struct ibv_recv_wr_1_0 **bad_recv_wr);
+	struct ibv_qp *		(*create_qp)(struct ibv_pd *pd, struct ibv_qp_init_attr *attr);
+	int			(*query_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+					    enum ibv_qp_attr_mask attr_mask,
+					    struct ibv_qp_init_attr *init_attr);
+	int			(*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+					     enum ibv_qp_attr_mask attr_mask);
+	int			(*destroy_qp)(struct ibv_qp *qp);
+	int			(*post_send)(struct ibv_qp_1_0 *qp,
+					     struct ibv_send_wr_1_0 *wr,
+					     struct ibv_send_wr_1_0 **bad_wr);
+	int			(*post_recv)(struct ibv_qp_1_0 *qp,
+					     struct ibv_recv_wr_1_0 *wr,
+					     struct ibv_recv_wr_1_0 **bad_wr);
+	struct ibv_ah *		(*create_ah)(struct ibv_pd *pd, struct ibv_ah_attr *attr);
+	int			(*destroy_ah)(struct ibv_ah *ah);
+	int			(*attach_mcast)(struct ibv_qp *qp, union ibv_gid *gid,
+						uint16_t lid);
+	int			(*detach_mcast)(struct ibv_qp *qp, union ibv_gid *gid,
+						uint16_t lid);
+};
+
+struct ibv_context_1_0 {
+	struct ibv_device_1_0	       *device;
+	struct ibv_context_ops_1_0	ops;
+	int				cmd_fd;
+	int				async_fd;
+	int				num_comp_vectors;
+
+	struct ibv_context	       *real_context; /* was abi_compat member */
+};
+
+struct ibv_device_1_0 **__ibv_get_device_list_1_0(int *num)
+{
+	struct ibv_device **real_list;
+	struct ibv_device_1_0 **l;
+	int i, n;
+
+	real_list = ibv_get_device_list(&n);
+	if (!real_list)
+		return NULL;
+
+	l = calloc(n + 2, sizeof (struct ibv_device_1_0 *));
+	if (!l)
+		return NULL;
+
+	l[0] = (void *) real_list;
+
+	for (i = 0; i < n; ++i) {
+		l[i + 1] = calloc(1, sizeof (struct ibv_device_1_0));
+		if (!l[i + 1])
+			goto fail;
+		l[i + 1]->real_device = real_list[i];
+	}
+
+	if (num)
+		*num = n;
+
+	return l + 1;
+
+fail:
+	for (i = 1; i <= n; ++i)
+		if (l[i])
+			free(l[i]);
+	ibv_free_device_list(real_list);
+	return NULL;
+}
+symver(__ibv_get_device_list_1_0, ibv_get_device_list, IBVERBS_1.0);
+
+void __ibv_free_device_list_1_0(struct ibv_device_1_0 **list)
+{
+	struct ibv_device_1_0 **l = list;
+
+	while (*l++)
+		free(l);
+
+	ibv_free_device_list((void *) list[-1]);
+	free(list - 1);
+}
+symver(__ibv_free_device_list_1_0, ibv_free_device_list, IBVERBS_1.0);
+
+const char *__ibv_get_device_name_1_0(struct ibv_device_1_0 *device)
+{
+	return ibv_get_device_name(device->real_device);
+}
+symver(__ibv_get_device_name_1_0, ibv_get_device_name, IBVERBS_1.0);
+
+uint64_t __ibv_get_device_guid_1_0(struct ibv_device_1_0 *device)
+{
+	return ibv_get_device_guid(device->real_device);
+}
+symver(__ibv_get_device_guid_1_0, ibv_get_device_guid, IBVERBS_1.0);
+
+static int poll_cq_wrapper_1_0(struct ibv_cq_1_0 *cq, int num_entries,
+			       struct ibv_wc *wc)
+{
+	return cq->context->real_context->ops.poll_cq(cq->real_cq, num_entries, wc);
+}
+
+static int req_notify_cq_wrapper_1_0(struct ibv_cq_1_0 *cq, int sol_only)
+{
+	return cq->context->real_context->ops.req_notify_cq(cq->real_cq, sol_only);
+}
+
+static int post_srq_recv_wrapper_1_0(struct ibv_srq_1_0 *srq, struct ibv_recv_wr_1_0 *wr,
+				 struct ibv_recv_wr_1_0 **bad_wr)
+{
+	struct ibv_recv_wr_1_0 *w;
+	struct ibv_recv_wr *real_wr = NULL, *head_wr, *tail_wr = NULL, *real_bad_wr;
+	int ret;
+
+	for (w = wr; w; w = w->next) {
+		real_wr = alloca(sizeof *real_wr);
+		real_wr->wr_id   = w->wr_id;
+		real_wr->sg_list = w->sg_list;
+		real_wr->num_sge = w->num_sge;
+		real_wr->next    = NULL;
+		if (tail_wr)
+			tail_wr->next = real_wr;
+		else
+			head_wr = real_wr;
+
+		tail_wr = real_wr;
+	}
+
+	ret = srq->context->real_context->ops.post_srq_recv(srq->real_srq, real_wr,
+							    &real_bad_wr);
+
+	if (ret) {
+		/*XXX set bad_wr*/
+	}
+
+	return ret;
+}
+
+static int post_send_wrapper_1_0(struct ibv_qp_1_0 *qp, struct ibv_send_wr_1_0 *wr,
+				 struct ibv_send_wr_1_0 **bad_wr)
+{
+	struct ibv_send_wr_1_0 *w;
+	struct ibv_send_wr *real_wr = NULL, *head_wr, *tail_wr = NULL, *real_bad_wr;
+	int is_ud = qp->qp_type == IBV_QPT_UD;
+	int ret;
+
+	for (w = wr; w; w = w->next) {
+		real_wr = alloca(sizeof *real_wr);
+		real_wr->wr_id = w->wr_id;
+		real_wr->next  = NULL;
+
+		memcpy(&real_wr->sg_list, &w->sg_list,
+		       sizeof *w - offsetof(struct ibv_send_wr, sg_list));
+
+		if (is_ud)
+			real_wr->wr.ud.ah = w->wr.ud.ah->real_ah;
+
+		if (tail_wr)
+			tail_wr->next = real_wr;
+		else
+			head_wr = real_wr;
+
+		tail_wr = real_wr;
+	}
+
+	ret = qp->context->real_context->ops.post_send(qp->real_qp, real_wr,
+						       &real_bad_wr);
+
+	if (ret) {
+		/*XXX set bad_wr*/
+	}
+
+	return ret;
+}
+
+static int post_recv_wrapper_1_0(struct ibv_qp_1_0 *qp, struct ibv_recv_wr_1_0 *wr,
+				 struct ibv_recv_wr_1_0 **bad_wr)
+{
+	struct ibv_recv_wr_1_0 *w;
+	struct ibv_recv_wr *real_wr = NULL, *head_wr, *tail_wr = NULL, *real_bad_wr;
+	int ret;
+
+	for (w = wr; w; w = w->next) {
+		real_wr = alloca(sizeof *real_wr);
+		real_wr->wr_id   = w->wr_id;
+		real_wr->sg_list = w->sg_list;
+		real_wr->num_sge = w->num_sge;
+		real_wr->next    = NULL;
+		if (tail_wr)
+			tail_wr->next = real_wr;
+		else
+			head_wr = real_wr;
+
+		tail_wr = real_wr;
+	}
+
+	ret = qp->context->real_context->ops.post_recv(qp->real_qp, real_wr,
+						       &real_bad_wr);
+
+	if (ret) {
+		/*XXX set bad_wr*/
+	}
+
+	return ret;
+}
+
+struct ibv_context_1_0 *__ibv_open_device_1_0(struct ibv_device_1_0 *device)
+{
+	struct ibv_context     *real_ctx;
+	struct ibv_context_1_0 *ctx;
+
+	ctx = malloc(sizeof *ctx);
+	if (!ctx)
+		return NULL;
+
+	real_ctx = ibv_open_device(device->real_device);
+	if (!real_ctx) {
+		free(ctx);
+		return NULL;
+	}
+
+	ctx->device       = device;
+	ctx->real_context = real_ctx;
+
+	ctx->ops.poll_cq       = poll_cq_wrapper_1_0;
+	ctx->ops.req_notify_cq = req_notify_cq_wrapper_1_0;
+	ctx->ops.post_send     = post_send_wrapper_1_0;
+	ctx->ops.post_recv     = post_recv_wrapper_1_0;
+	ctx->ops.post_srq_recv = post_srq_recv_wrapper_1_0;
+
+	return ctx;
+}
+symver(__ibv_open_device_1_0, ibv_open_device, IBVERBS_1.0);
+
+int __ibv_close_device_1_0(struct ibv_context_1_0 *context)
+{
+	int ret;
+
+	ret = ibv_close_device(context->real_context);
+	if (ret)
+		return ret;
+
+	free(context);
+	return 0;
+}
+symver(__ibv_close_device_1_0, ibv_close_device, IBVERBS_1.0);
+
+int __ibv_get_async_event_1_0(struct ibv_context_1_0 *context,
+			      struct ibv_async_event *event)
+{
+	int ret;
+
+	ret = ibv_get_async_event(context->real_context, event);
+	if (ret)
+		return ret;
+
+	switch (event->event_type) {
+	case IBV_EVENT_CQ_ERR:
+		event->element.cq = event->element.cq->cq_context;
+		break;
+
+	case IBV_EVENT_QP_FATAL:
+	case IBV_EVENT_QP_REQ_ERR:
+	case IBV_EVENT_QP_ACCESS_ERR:
+	case IBV_EVENT_COMM_EST:
+	case IBV_EVENT_SQ_DRAINED:
+	case IBV_EVENT_PATH_MIG:
+	case IBV_EVENT_PATH_MIG_ERR:
+	case IBV_EVENT_QP_LAST_WQE_REACHED:
+		event->element.qp = event->element.qp->qp_context;
+		break;
+
+	case IBV_EVENT_SRQ_ERR:
+	case IBV_EVENT_SRQ_LIMIT_REACHED:
+		event->element.srq = event->element.srq->srq_context;
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+symver(__ibv_get_async_event_1_0, ibv_get_async_event, IBVERBS_1.0);
+
+void __ibv_ack_async_event_1_0(struct ibv_async_event *event)
+{
+	struct ibv_async_event real_event = *event;
+
+	switch (event->event_type) {
+	case IBV_EVENT_CQ_ERR:
+		real_event.element.cq =
+			((struct ibv_cq_1_0 *) event->element.cq)->real_cq;
+		break;
+
+	case IBV_EVENT_QP_FATAL:
+	case IBV_EVENT_QP_REQ_ERR:
+	case IBV_EVENT_QP_ACCESS_ERR:
+	case IBV_EVENT_COMM_EST:
+	case IBV_EVENT_SQ_DRAINED:
+	case IBV_EVENT_PATH_MIG:
+	case IBV_EVENT_PATH_MIG_ERR:
+	case IBV_EVENT_QP_LAST_WQE_REACHED:
+		real_event.element.qp =
+			((struct ibv_qp_1_0 *) event->element.qp)->real_qp;
+		break;
+
+	case IBV_EVENT_SRQ_ERR:
+	case IBV_EVENT_SRQ_LIMIT_REACHED:
+		real_event.element.srq =
+			((struct ibv_srq_1_0 *) event->element.srq)->real_srq;
+		break;
+
+	default:
+		break;
+	}
+
+	ibv_ack_async_event(&real_event);
+}
+symver(__ibv_ack_async_event_1_0, ibv_ack_async_event, IBVERBS_1.0);
+
+int __ibv_query_device_1_0(struct ibv_context_1_0 *context,
+			   struct ibv_device_attr *device_attr)
+{
+	return ibv_query_device(context->real_context, device_attr);
+}
+symver(__ibv_query_device_1_0, ibv_query_device, IBVERBS_1.0);
+
+int __ibv_query_port_1_0(struct ibv_context_1_0 *context, uint8_t port_num,
+			 struct ibv_port_attr *port_attr)
+{
+	return ibv_query_port(context->real_context, port_num, port_attr);
+}
+symver(__ibv_query_port_1_0, ibv_query_port, IBVERBS_1.0);
+
+int __ibv_query_gid_1_0(struct ibv_context_1_0 *context, uint8_t port_num,
+			int index, union ibv_gid *gid)
+{
+	return ibv_query_gid(context->real_context, port_num, index, gid);
+}
+symver(__ibv_query_gid_1_0, ibv_query_gid, IBVERBS_1.0);
+
+int __ibv_query_pkey_1_0(struct ibv_context_1_0 *context, uint8_t port_num,
+			 int index, uint16_t *pkey)
+{
+	return ibv_query_pkey(context->real_context, port_num, index, pkey);
+}
+symver(__ibv_query_pkey_1_0, ibv_query_pkey, IBVERBS_1.0);
+
+struct ibv_pd_1_0 *__ibv_alloc_pd_1_0(struct ibv_context_1_0 *context)
+{
+	struct ibv_pd *real_pd;
+	struct ibv_pd_1_0 *pd;
+
+	pd = malloc(sizeof *pd);
+	if (!pd)
+		return NULL;
+
+	real_pd = ibv_alloc_pd(context->real_context);
+	if (!real_pd) {
+		free(pd);
+		return NULL;
+	}
+
+	pd->context = context;
+	pd->real_pd = real_pd;
+
+	return pd;
+}
+symver(__ibv_alloc_pd_1_0, ibv_alloc_pd, IBVERBS_1.0);
+
+int __ibv_dealloc_pd_1_0(struct ibv_pd_1_0 *pd)
+{
+	int ret;
+
+	ret = ibv_dealloc_pd(pd->real_pd);
+	if (ret)
+		return ret;
+
+	free(pd);
+	return 0;
+}
+symver(__ibv_dealloc_pd_1_0, ibv_dealloc_pd, IBVERBS_1.0);
+
+struct ibv_mr_1_0 *__ibv_reg_mr_1_0(struct ibv_pd_1_0 *pd, void *addr,
+				    size_t length, enum ibv_access_flags access)
+{
+	struct ibv_mr *real_mr;
+	struct ibv_mr_1_0 *mr;
+
+	mr = malloc(sizeof *mr);
+	if (!mr)
+		return NULL;
+
+	real_mr = ibv_reg_mr(pd->real_pd, addr, length, access);
+	if (!real_mr) {
+		free(mr);
+		return NULL;
+	}
+
+	mr->context = pd->context;
+	mr->pd      = pd;
+	mr->lkey    = real_mr->lkey;
+	mr->rkey    = real_mr->rkey;
+	mr->real_mr = real_mr;
+
+	return mr;
+}
+symver(__ibv_reg_mr_1_0, ibv_reg_mr, IBVERBS_1.0);
+
+int __ibv_dereg_mr_1_0(struct ibv_mr_1_0 *mr)
+{
+	int ret;
+
+	ret = ibv_dereg_mr(mr->real_mr);
+	if (ret)
+		return ret;
+
+	free(mr);
+	return 0;
+}
+symver(__ibv_dereg_mr_1_0, ibv_dereg_mr, IBVERBS_1.0);
+
+struct ibv_cq_1_0 *__ibv_create_cq_1_0(struct ibv_context_1_0 *context, int cqe,
+				       void *cq_context,
+				       struct ibv_comp_channel *channel,
+				       int comp_vector)
+{
+	struct ibv_cq *real_cq;
+	struct ibv_cq_1_0 *cq;
+
+	cq = malloc(sizeof *cq);
+	if (!cq)
+		return NULL;
+
+	real_cq = ibv_create_cq(context->real_context, cqe, cq_context,
+				channel, comp_vector);
+	if (!real_cq) {
+		free(cq);
+		return NULL;
+	}
+
+	cq->context    = context;
+	cq->cq_context = cq_context;
+	cq->cqe        = cqe;
+	cq->real_cq    = real_cq;
+
+	real_cq->cq_context = cq;
+
+	return cq;
+}
+symver(__ibv_create_cq_1_0, ibv_create_cq, IBVERBS_1.0);
+
+int __ibv_resize_cq_1_0(struct ibv_cq_1_0 *cq, int cqe)
+{
+	return ibv_resize_cq(cq->real_cq, cqe);
+}
+symver(__ibv_resize_cq_1_0, ibv_resize_cq, IBVERBS_1.0);
+
+int __ibv_destroy_cq_1_0(struct ibv_cq_1_0 *cq)
+{
+	int ret;
+
+	ret = ibv_destroy_cq(cq->real_cq);
+	if (ret)
+		return ret;
+
+	free(cq);
+	return 0;
+}
+symver(__ibv_destroy_cq_1_0, ibv_destroy_cq, IBVERBS_1.0);
+
+int __ibv_get_cq_event_1_0(struct ibv_comp_channel *channel,
+			   struct ibv_cq_1_0 **cq, void **cq_context)
+{
+	struct ibv_cq *real_cq;
+	void *cq_ptr;
+	int ret;
+
+	ret = ibv_get_cq_event(channel, &real_cq, &cq_ptr);
+	if (ret)
+		return ret;
+
+	*cq         = cq_ptr;
+	*cq_context = (*cq)->cq_context;
+
+	return 0;
+}
+symver(__ibv_get_cq_event_1_0, ibv_get_cq_event, IBVERBS_1.0);
+
+void __ibv_ack_cq_events_1_0(struct ibv_cq_1_0 *cq, unsigned int nevents)
+{
+	ibv_ack_cq_events(cq->real_cq, nevents);
+}
+symver(__ibv_ack_cq_events_1_0, ibv_ack_cq_events, IBVERBS_1.0);
+
+struct ibv_srq_1_0 *__ibv_create_srq_1_0(struct ibv_pd_1_0 *pd,
+					 struct ibv_srq_init_attr *srq_init_attr)
+{
+	struct ibv_srq *real_srq;
+	struct ibv_srq_1_0 *srq;
+
+	srq = malloc(sizeof *srq);
+	if (!srq)
+		return NULL;
+
+	real_srq = ibv_create_srq(pd->real_pd, srq_init_attr);
+	if (!real_srq) {
+		free(srq);
+		return NULL;
+	}
+
+	srq->context     = pd->context;
+	srq->srq_context = srq_init_attr->srq_context;
+	srq->pd          = pd;
+	srq->real_srq    = real_srq;
+
+	real_srq->srq_context = srq;
+
+	return srq;
+}
+symver(__ibv_create_srq_1_0, ibv_create_srq, IBVERBS_1.0);
+
+int __ibv_modify_srq_1_0(struct ibv_srq_1_0 *srq,
+			 struct ibv_srq_attr *srq_attr,
+			 enum ibv_srq_attr_mask srq_attr_mask)
+{
+	return ibv_modify_srq(srq->real_srq, srq_attr, srq_attr_mask);
+}
+symver(__ibv_modify_srq_1_0, ibv_modify_srq, IBVERBS_1.0);
+
+int __ibv_query_srq_1_0(struct ibv_srq_1_0 *srq, struct ibv_srq_attr *srq_attr)
+{
+	return ibv_query_srq(srq->real_srq, srq_attr);
+}
+symver(__ibv_query_srq_1_0, ibv_query_srq, IBVERBS_1.0);
+
+int __ibv_destroy_srq_1_0(struct ibv_srq_1_0 *srq)
+{
+	int ret;
+
+	ret = ibv_destroy_srq(srq->real_srq);
+	if (ret)
+		return ret;
+
+	free(srq);
+	return 0;
+}
+symver(__ibv_destroy_srq_1_0, ibv_destroy_srq, IBVERBS_1.0);
+
+struct ibv_qp_1_0 *__ibv_create_qp_1_0(struct ibv_pd_1_0 *pd,
+				       struct ibv_qp_init_attr_1_0 *qp_init_attr)
+{
+	struct ibv_qp *real_qp;
+	struct ibv_qp_1_0 *qp;
+	struct ibv_qp_init_attr real_init_attr;
+
+	qp = malloc(sizeof *qp);
+	if (!qp)
+		return NULL;
+
+	real_init_attr.qp_context = qp_init_attr->qp_context;
+	real_init_attr.send_cq    = qp_init_attr->send_cq->real_cq;
+	real_init_attr.recv_cq    = qp_init_attr->recv_cq->real_cq;
+	real_init_attr.srq        = qp_init_attr->srq ?
+		qp_init_attr->srq->real_srq : NULL;
+	real_init_attr.cap        = qp_init_attr->cap;
+	real_init_attr.qp_type    = qp_init_attr->qp_type;
+	real_init_attr.sq_sig_all = qp_init_attr->sq_sig_all;
+
+	real_qp = ibv_create_qp(pd->real_pd, &real_init_attr);
+	if (!real_qp) {
+		free(qp);
+		return NULL;
+	}
+
+	qp->context    = pd->context;
+	qp->qp_context = qp_init_attr->qp_context;
+	qp->pd         = pd;
+	qp->send_cq    = qp_init_attr->send_cq;
+	qp->recv_cq    = qp_init_attr->recv_cq;
+	qp->srq        = qp_init_attr->srq;
+	qp->qp_type    = qp_init_attr->qp_type;
+	qp->qp_num     = real_qp->qp_num;
+	qp->real_qp    = real_qp;
+
+	real_qp->qp_context = qp;
+
+	return qp;
+}
+symver(__ibv_create_qp_1_0, ibv_create_qp, IBVERBS_1.0);
+
+int __ibv_query_qp_1_0(struct ibv_qp_1_0 *qp, struct ibv_qp_attr *attr,
+		       enum ibv_qp_attr_mask attr_mask,
+		       struct ibv_qp_init_attr_1_0 *init_attr)
+{
+	struct ibv_qp_init_attr real_init_attr;
+	int ret;
+
+	ret = ibv_query_qp(qp->real_qp, attr, attr_mask, &real_init_attr);
+	if (ret)
+		return ret;
+
+	init_attr->qp_context = qp->qp_context;
+	init_attr->send_cq    = real_init_attr.send_cq->cq_context;
+	init_attr->recv_cq    = real_init_attr.recv_cq->cq_context;
+	init_attr->srq        = real_init_attr.srq->srq_context;
+	init_attr->qp_type    = real_init_attr.qp_type;
+	init_attr->cap        = real_init_attr.cap;
+	init_attr->sq_sig_all = real_init_attr.sq_sig_all;
+
+	return 0;
+}
+symver(__ibv_query_qp_1_0, ibv_query_qp, IBVERBS_1.0);
+
+int __ibv_modify_qp_1_0(struct ibv_qp_1_0 *qp, struct ibv_qp_attr *attr,
+			enum ibv_qp_attr_mask attr_mask)
+{
+	return ibv_modify_qp(qp->real_qp, attr, attr_mask);
+}
+symver(__ibv_modify_qp_1_0, ibv_modify_qp, IBVERBS_1.0);
+
+int __ibv_destroy_qp_1_0(struct ibv_qp_1_0 *qp)
+{
+	int ret;
+
+	ret = ibv_destroy_qp(qp->real_qp);
+	if (ret)
+		return ret;
+
+	free(qp);
+	return 0;
+}
+symver(__ibv_destroy_qp_1_0, ibv_destroy_qp, IBVERBS_1.0);
+
+struct ibv_ah_1_0 *__ibv_create_ah_1_0(struct ibv_pd_1_0 *pd,
+				       struct ibv_ah_attr *attr)
+{
+	struct ibv_ah *real_ah;
+	struct ibv_ah_1_0 *ah;
+
+	ah = malloc(sizeof *ah);
+	if (!ah)
+		return NULL;
+
+	real_ah = ibv_create_ah(pd->real_pd, attr);
+	if (!real_ah) {
+		free(ah);
+		return NULL;
+	}
+
+	ah->context = pd->context;
+	ah->pd      = pd;
+	ah->real_ah = real_ah;
+
+	return ah;
+}
+symver(__ibv_create_ah_1_0, ibv_create_ah, IBVERBS_1.0);
+
+int __ibv_destroy_ah_1_0(struct ibv_ah_1_0 *ah)
+{
+	int ret;
+
+	ret = ibv_destroy_ah(ah->real_ah);
+	if (ret)
+		return ret;
+
+	free(ah);
+	return 0;
+}
+symver(__ibv_destroy_ah_1_0, ibv_destroy_ah, IBVERBS_1.0);
+
+int __ibv_attach_mcast_1_0(struct ibv_qp_1_0 *qp, union ibv_gid *gid, uint16_t lid)
+{
+	return ibv_attach_mcast(qp->real_qp, gid, lid);
+}
+symver(__ibv_attach_mcast_1_0, ibv_attach_mcast, IBVERBS_1.0);
+
+int __ibv_detach_mcast_1_0(struct ibv_qp_1_0 *qp, union ibv_gid *gid, uint16_t lid)
+{
+	return ibv_detach_mcast(qp->real_qp, gid, lid);
+}
+symver(__ibv_detach_mcast_1_0, ibv_detach_mcast, IBVERBS_1.0);
diff --git a/src/device.c b/src/device.c
index f4e4473..bca1ce9 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2006 Cisco Systems, Inc.  All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -52,7 +52,7 @@ static pthread_mutex_t device_list_lock = PTHREAD_MUTEX_INITIALIZER;
 static int num_devices;
 static struct ibv_device **device_list;
 
-struct ibv_device **ibv_get_device_list(int *num)
+struct ibv_device **__ibv_get_device_list(int *num)
 {
 	struct ibv_device **l;
 	int i;
@@ -77,18 +77,21 @@ out:
 
 	return l;
 }
+default_symver(__ibv_get_device_list, ibv_get_device_list);
 
-void ibv_free_device_list(struct ibv_device **list)
+void __ibv_free_device_list(struct ibv_device **list)
 {
 	free(list);
 }
+default_symver(__ibv_free_device_list, ibv_free_device_list);
 
-const char *ibv_get_device_name(struct ibv_device *device)
+const char *__ibv_get_device_name(struct ibv_device *device)
 {
 	return device->name;
 }
+default_symver(__ibv_get_device_name, ibv_get_device_name);
 
-uint64_t ibv_get_device_guid(struct ibv_device *device)
+uint64_t __ibv_get_device_guid(struct ibv_device *device)
 {
 	char attr[24];
 	uint64_t guid = 0;
@@ -108,8 +111,9 @@ uint64_t ibv_get_device_guid(struct ibv_device *device)
 
 	return htonll(guid);
 }
+default_symver(__ibv_get_device_guid, ibv_get_device_guid);
 
-struct ibv_context *ibv_open_device(struct ibv_device *device)
+struct ibv_context *__ibv_open_device(struct ibv_device *device)
 {
 	char *devpath;
 	int cmd_fd;
@@ -142,8 +146,9 @@ err:
 
 	return NULL;
 }
+default_symver(__ibv_open_device, ibv_open_device);
 
-int ibv_close_device(struct ibv_context *context)
+int __ibv_close_device(struct ibv_context *context)
 {
 	int async_fd = context->async_fd;
 	int cmd_fd   = context->cmd_fd;
@@ -164,9 +169,10 @@ int ibv_close_device(struct ibv_context *context)
 
 	return 0;
 }
+default_symver(__ibv_close_device, ibv_close_device);
 
-int ibv_get_async_event(struct ibv_context *context,
-			struct ibv_async_event *event)
+int __ibv_get_async_event(struct ibv_context *context,
+			  struct ibv_async_event *event)
 {
 	struct ibv_kern_async_event ev;
 
@@ -206,8 +212,9 @@ int ibv_get_async_event(struct ibv_context *context,
 
 	return 0;
 }
+default_symver(__ibv_get_async_event, ibv_get_async_event);
 
-void ibv_ack_async_event(struct ibv_async_event *event)
+void __ibv_ack_async_event(struct ibv_async_event *event)
 {
 	switch (event->event_type) {
 	case IBV_EVENT_CQ_ERR:
@@ -258,3 +265,4 @@ void ibv_ack_async_event(struct ibv_async_event *event)
 		return;
 	}
 }
+default_symver(__ibv_ack_async_event, ibv_ack_async_event);
diff --git a/src/ibverbs.h b/src/ibverbs.h
index 14330f8..b1d2c2b 100644
--- a/src/ibverbs.h
+++ b/src/ibverbs.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2007 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -56,6 +57,19 @@
 #define INIT		__attribute__((constructor))
 #define FINI		__attribute__((destructor))
 
+#define DEFAULT_ABI	"IBVERBS_1.1"
+
+#ifdef HAVE_SYMVER_SUPPORT
+#  define symver(name, api, ver) \
+	asm(".symver " #name "," #api "@" #ver)
+#  define default_symver(name, api) \
+	asm(".symver " #name "," #api "@@" DEFAULT_ABI)
+#else
+#  define symver(name, api, ver)
+#  define default_symver(name, api) \
+	extern __typeof(name) api __attribute__((alias(#name)))
+#endif /* HAVE_SYMVER_SUPPORT */
+
 #define PFX		"libibverbs: "
 
 struct ibv_abi_compat_v2 {
diff --git a/src/libibverbs.map b/src/libibverbs.map
index 795dd55..3a346ed 100644
--- a/src/libibverbs.map
+++ b/src/libibverbs.map
@@ -32,8 +32,6 @@ IBVERBS_1.0 {
 		ibv_modify_qp;
 		ibv_destroy_qp;
 		ibv_create_ah;
-		ibv_init_ah_from_wc;
-		ibv_create_ah_from_wc;
 		ibv_destroy_ah;
 		ibv_attach_mcast;
 		ibv_detach_mcast;
@@ -67,17 +65,30 @@ IBVERBS_1.0 {
 		ibv_cmd_attach_mcast;
 		ibv_cmd_detach_mcast;
 		ibv_copy_qp_attr_from_kern;
-		ibv_copy_ah_attr_from_kern;
 		ibv_copy_path_rec_from_kern;
 		ibv_copy_path_rec_to_kern;
 		ibv_rate_to_mult;
 		mult_to_ibv_rate;
 		ibv_get_sysfs_path;
 		ibv_read_sysfs_file;
+
+	local: *;
+};
+
+IBVERBS_1.1 {
+	global:
+		ibv_get_device_list;
+		ibv_free_device_list;
+		ibv_get_device_name;
+		ibv_get_device_guid;
+		ibv_open_device;
+		ibv_close_device;
+
+		ibv_init_ah_from_wc;
+		ibv_create_ah_from_wc;
+		ibv_copy_ah_attr_from_kern;
 		ibv_fork_init;
 		ibv_dontfork_range;
 		ibv_dofork_range;
 		ibv_register_driver;
-
-	local: *;
-};
+} IBVERBS_1.0;
diff --git a/src/verbs.c b/src/verbs.c
index 6ac56d3..56513e4 100644
--- a/src/verbs.c
+++ b/src/verbs.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2006 Cisco Systems, Inc.  All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -76,20 +76,22 @@ enum ibv_rate mult_to_ibv_rate(int mult)
 	}
 }
 
-int ibv_query_device(struct ibv_context *context,
-		     struct ibv_device_attr *device_attr)
+int __ibv_query_device(struct ibv_context *context,
+		       struct ibv_device_attr *device_attr)
 {
 	return context->ops.query_device(context, device_attr);
 }
+default_symver(__ibv_query_device, ibv_query_device);
 
-int ibv_query_port(struct ibv_context *context, uint8_t port_num,
-		   struct ibv_port_attr *port_attr)
+int __ibv_query_port(struct ibv_context *context, uint8_t port_num,
+		     struct ibv_port_attr *port_attr)
 {
 	return context->ops.query_port(context, port_num, port_attr);
 }
+default_symver(__ibv_query_port, ibv_query_port);
 
-int ibv_query_gid(struct ibv_context *context, uint8_t port_num,
-		  int index, union ibv_gid *gid)
+int __ibv_query_gid(struct ibv_context *context, uint8_t port_num,
+		    int index, union ibv_gid *gid)
 {
 	char name[24];
 	char attr[41];
@@ -111,9 +113,10 @@ int ibv_query_gid(struct ibv_context *context, uint8_t port_num,
 
 	return 0;
 }
+default_symver(__ibv_query_gid, ibv_query_gid);
 
-int ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
-		   int index, uint16_t *pkey)
+int __ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
+		     int index, uint16_t *pkey)
 {
 	char name[24];
 	char attr[8];
@@ -131,8 +134,9 @@ int ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
 	*pkey = htons(val);
 	return 0;
 }
+default_symver(__ibv_query_pkey, ibv_query_pkey);
 
-struct ibv_pd *ibv_alloc_pd(struct ibv_context *context)
+struct ibv_pd *__ibv_alloc_pd(struct ibv_context *context)
 {
 	struct ibv_pd *pd;
 
@@ -142,14 +146,16 @@ struct ibv_pd *ibv_alloc_pd(struct ibv_context *context)
 
 	return pd;
 }
+default_symver(__ibv_alloc_pd, ibv_alloc_pd);
 
-int ibv_dealloc_pd(struct ibv_pd *pd)
+int __ibv_dealloc_pd(struct ibv_pd *pd)
 {
 	return pd->context->ops.dealloc_pd(pd);
 }
+default_symver(__ibv_dealloc_pd, ibv_dealloc_pd);
 
-struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr,
-			  size_t length, enum ibv_access_flags access)
+struct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr,
+			    size_t length, enum ibv_access_flags access)
 {
 	struct ibv_mr *mr;
 
@@ -167,8 +173,9 @@ struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr,
 
 	return mr;
 }
+default_symver(__ibv_reg_mr, ibv_reg_mr);
 
-int ibv_dereg_mr(struct ibv_mr *mr)
+int __ibv_dereg_mr(struct ibv_mr *mr)
 {
 	int ret;
 	void *addr	= mr->addr;
@@ -180,6 +187,7 @@ int ibv_dereg_mr(struct ibv_mr *mr)
 
 	return ret;
 }
+default_symver(__ibv_dereg_mr, ibv_dereg_mr);
 
 static struct ibv_comp_channel *ibv_create_comp_channel_v2(struct ibv_context *context)
 {
@@ -241,8 +249,8 @@ int ibv_destroy_comp_channel(struct ibv_comp_channel *channel)
 	return 0;
 }
 
-struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context,
-			     struct ibv_comp_channel *channel, int comp_vector)
+struct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context,
+			       struct ibv_comp_channel *channel, int comp_vector)
 {
 	struct ibv_cq *cq = context->ops.create_cq(context, cqe, channel,
 						   comp_vector);
@@ -258,23 +266,25 @@ struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, void *cq_cont
 
 	return cq;
 }
+default_symver(__ibv_create_cq, ibv_create_cq);
 
-int ibv_resize_cq(struct ibv_cq *cq, int cqe)
+int __ibv_resize_cq(struct ibv_cq *cq, int cqe)
 {
 	if (!cq->context->ops.resize_cq)
 		return ENOSYS;
 
 	return cq->context->ops.resize_cq(cq, cqe);
 }
+default_symver(__ibv_resize_cq, ibv_resize_cq);
 
-int ibv_destroy_cq(struct ibv_cq *cq)
+int __ibv_destroy_cq(struct ibv_cq *cq)
 {
 	return cq->context->ops.destroy_cq(cq);
 }
+default_symver(__ibv_destroy_cq, ibv_destroy_cq);
 
-
-int ibv_get_cq_event(struct ibv_comp_channel *channel,
-		     struct ibv_cq **cq, void **cq_context)
+int __ibv_get_cq_event(struct ibv_comp_channel *channel,
+		       struct ibv_cq **cq, void **cq_context)
 {
 	struct ibv_comp_event ev;
 
@@ -289,17 +299,19 @@ int ibv_get_cq_event(struct ibv_comp_channel *channel,
 
 	return 0;
 }
+default_symver(__ibv_get_cq_event, ibv_get_cq_event);
 
-void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
+void __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
 {
 	pthread_mutex_lock(&cq->mutex);
 	cq->comp_events_completed += nevents;
 	pthread_cond_signal(&cq->cond);
 	pthread_mutex_unlock(&cq->mutex);
 }
+default_symver(__ibv_ack_cq_events, ibv_ack_cq_events);
 
-struct ibv_srq *ibv_create_srq(struct ibv_pd *pd,
-			       struct ibv_srq_init_attr *srq_init_attr)
+struct ibv_srq *__ibv_create_srq(struct ibv_pd *pd,
+				 struct ibv_srq_init_attr *srq_init_attr)
 {
 	struct ibv_srq *srq;
 
@@ -318,26 +330,30 @@ struct ibv_srq *ibv_create_srq(struct ibv_pd *pd,
 
 	return srq;
 }
+default_symver(__ibv_create_srq, ibv_create_srq);
 
-int ibv_modify_srq(struct ibv_srq *srq,
-		   struct ibv_srq_attr *srq_attr,
-		   enum ibv_srq_attr_mask srq_attr_mask)
+int __ibv_modify_srq(struct ibv_srq *srq,
+		     struct ibv_srq_attr *srq_attr,
+		     enum ibv_srq_attr_mask srq_attr_mask)
 {
 	return srq->context->ops.modify_srq(srq, srq_attr, srq_attr_mask);
 }
+default_symver(__ibv_modify_srq, ibv_modify_srq);
 
-int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr)
+int __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr)
 {
 	return srq->context->ops.query_srq(srq, srq_attr);
 }
+default_symver(__ibv_query_srq, ibv_query_srq);
 
-int ibv_destroy_srq(struct ibv_srq *srq)
+int __ibv_destroy_srq(struct ibv_srq *srq)
 {
 	return srq->context->ops.destroy_srq(srq);
 }
+default_symver(__ibv_destroy_srq, ibv_destroy_srq);
 
-struct ibv_qp *ibv_create_qp(struct ibv_pd *pd,
-			     struct ibv_qp_init_attr *qp_init_attr)
+struct ibv_qp *__ibv_create_qp(struct ibv_pd *pd,
+			       struct ibv_qp_init_attr *qp_init_attr)
 {
 	struct ibv_qp *qp = pd->context->ops.create_qp(pd, qp_init_attr);
 
@@ -356,10 +372,11 @@ struct ibv_qp *ibv_create_qp(struct ibv_pd *pd,
 
 	return qp;
 }
+default_symver(__ibv_create_qp, ibv_create_qp);
 
-int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
-		 enum ibv_qp_attr_mask attr_mask,
-		 struct ibv_qp_init_attr *init_attr)
+int __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+		   enum ibv_qp_attr_mask attr_mask,
+		   struct ibv_qp_init_attr *init_attr)
 {
 	int ret;
 
@@ -372,9 +389,10 @@ int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
 
 	return 0;
 }
+default_symver(__ibv_query_qp, ibv_query_qp);
 
-int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
-		  enum ibv_qp_attr_mask attr_mask)
+int __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+		    enum ibv_qp_attr_mask attr_mask)
 {
 	int ret;
 
@@ -387,13 +405,15 @@ int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
 
 	return 0;
 }
+default_symver(__ibv_modify_qp, ibv_modify_qp);
 
-int ibv_destroy_qp(struct ibv_qp *qp)
+int __ibv_destroy_qp(struct ibv_qp *qp)
 {
 	return qp->context->ops.destroy_qp(qp);
 }
+default_symver(__ibv_destroy_qp, ibv_destroy_qp);
 
-struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
+struct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
 {
 	struct ibv_ah *ah = pd->context->ops.create_ah(pd, attr);
 
@@ -404,6 +424,7 @@ struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
 
 	return ah;
 }
+default_symver(__ibv_create_ah, ibv_create_ah);
 
 static int ibv_find_gid_index(struct ibv_context *context, uint8_t port_num,
 			      union ibv_gid *gid)
@@ -461,17 +482,20 @@ struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc,
 	return ibv_create_ah(pd, &ah_attr);
 }
 
-int ibv_destroy_ah(struct ibv_ah *ah)
+int __ibv_destroy_ah(struct ibv_ah *ah)
 {
 	return ah->context->ops.destroy_ah(ah);
 }
+default_symver(__ibv_destroy_ah, ibv_destroy_ah);
 
-int ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)
+int __ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)
 {
 	return qp->context->ops.attach_mcast(qp, gid, lid);
 }
+default_symver(__ibv_attach_mcast, ibv_attach_mcast);
 
-int ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)
+int __ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)
 {
 	return qp->context->ops.detach_mcast(qp, gid, lid);
 }
+default_symver(__ibv_detach_mcast, ibv_detach_mcast);
-- 
1.4.4.1




More information about the general mailing list