#This patch was developed both in-house and from outside. We plan to submit it
#upstream, but do not yet have a target date for doing so
#
# HG changeset patch
# User alex.chiu@oracle.com
# Parent 688b7fd31600bd6dd04f6f7bf85df804730410e8
Shared PD and FMR specific patch.
diff -r 688b7fd31600 Makefile.am
--- a/Makefile.am Tue Nov 24 11:26:20 2015 -0800
+++ b/Makefile.am Tue Nov 24 20:12:48 2015 -0800
@@ -11,24 +11,29 @@
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/enum_strs.c src/solaris_compatibility.c
+ src/enum_strs.c
src_libibverbs_la_LDFLAGS = -version-info 1 -export-dynamic \
$(libibverbs_version_script)
src_libibverbs_la_DEPENDENCIES = $(srcdir)/src/libibverbs.map
bin_PROGRAMS = examples/ibv_devices examples/ibv_devinfo \
+ examples/ibv_frc_pingpong examples/ibv_shpd_pingpong \
examples/ibv_asyncwatch examples/ibv_rc_pingpong examples/ibv_uc_pingpong \
examples/ibv_ud_pingpong examples/ibv_srq_pingpong examples/ibv_xsrq_pingpong
examples_ibv_devices_SOURCES = examples/device_list.c
examples_ibv_devices_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_devinfo_SOURCES = examples/devinfo.c
examples_ibv_devinfo_LDADD = $(top_builddir)/src/libibverbs.la
+examples_ibv_frc_pingpong_SOURCES = examples/frc_pingpong.c examples/pingpong.c
+examples_ibv_frc_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_rc_pingpong_SOURCES = examples/rc_pingpong.c examples/pingpong.c
examples_ibv_rc_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_uc_pingpong_SOURCES = examples/uc_pingpong.c examples/pingpong.c
examples_ibv_uc_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_ud_pingpong_SOURCES = examples/ud_pingpong.c examples/pingpong.c
examples_ibv_ud_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
+examples_ibv_shpd_pingpong_SOURCES = examples/shpd_pingpong.c examples/pingpong.c
+examples_ibv_shpd_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_srq_pingpong_SOURCES = examples/srq_pingpong.c examples/pingpong.c
examples_ibv_srq_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_xsrq_pingpong_SOURCES = examples/xsrq_pingpong.c examples/pingpong.c
@@ -40,9 +45,10 @@
libibverbsinclude_HEADERS = include/infiniband/arch.h include/infiniband/driver.h \
include/infiniband/kern-abi.h include/infiniband/opcode.h include/infiniband/verbs.h \
- include/infiniband/sa-kern-abi.h include/infiniband/sa.h include/infiniband/marshall.h include/infiniband/ofa_solaris.h
+ include/infiniband/sa-kern-abi.h include/infiniband/sa.h include/infiniband/marshall.h
man_MANS = man/ibv_asyncwatch.1 man/ibv_devices.1 man/ibv_devinfo.1 \
+ man/ibv_shpd_pingpong.1 \
man/ibv_rc_pingpong.1 man/ibv_uc_pingpong.1 man/ibv_ud_pingpong.1 \
man/ibv_srq_pingpong.1 man/ibv_alloc_pd.3 man/ibv_attach_mcast.3 \
man/ibv_create_ah.3 man/ibv_create_ah_from_wc.3 \
@@ -67,7 +73,6 @@
EXTRA_DIST = include/infiniband/driver.h include/infiniband/kern-abi.h \
include/infiniband/opcode.h include/infiniband/verbs.h include/infiniband/marshall.h \
- include/infiniband/ofa_solaris.h \
include/infiniband/sa-kern-abi.h include/infiniband/sa.h \
src/ibverbs.h examples/pingpong.h \
src/libibverbs.map libibverbs.spec.in $(man_MANS)
diff -r 688b7fd31600 Makefile.in
--- a/Makefile.in Tue Nov 24 11:26:20 2015 -0800
+++ b/Makefile.in Tue Nov 24 20:12:48 2015 -0800
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -17,17 +17,7 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -92,12 +82,25 @@
host_triplet = @host@
bin_PROGRAMS = examples/ibv_devices$(EXEEXT) \
examples/ibv_devinfo$(EXEEXT) examples/ibv_asyncwatch$(EXEEXT) \
+ examples/ibv_frc_pingpong$(EXEEXT) \
+ examples/ibv_shpd_pingpong$(EXEEXT) \
examples/ibv_rc_pingpong$(EXEEXT) \
examples/ibv_uc_pingpong$(EXEEXT) \
examples/ibv_ud_pingpong$(EXEEXT) \
examples/ibv_srq_pingpong$(EXEEXT) \
examples/ibv_xsrq_pingpong$(EXEEXT)
subdir = .
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/configure $(am__configure_deps) \
+ $(srcdir)/config.h.in $(srcdir)/libibverbs.spec.in \
+ $(top_srcdir)/config/depcomp $(libibverbsinclude_HEADERS) \
+ AUTHORS COPYING ChangeLog README config/compile \
+ config/config.guess config/config.sub config/depcomp \
+ config/install-sh config/missing config/ltmain.sh \
+ $(top_srcdir)/config/compile $(top_srcdir)/config/config.guess \
+ $(top_srcdir)/config/config.sub \
+ $(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \
+ $(top_srcdir)/config/missing
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \
$(top_srcdir)/config/ltoptions.m4 \
@@ -106,9 +109,6 @@
$(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
- $(am__configure_deps) $(libibverbsinclude_HEADERS) \
- $(am__DIST_COMMON)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
@@ -177,12 +177,24 @@
am_examples_ibv_devinfo_OBJECTS = examples/devinfo.$(OBJEXT)
examples_ibv_devinfo_OBJECTS = $(am_examples_ibv_devinfo_OBJECTS)
examples_ibv_devinfo_DEPENDENCIES = $(top_builddir)/src/libibverbs.la
+am_examples_ibv_frc_pingpong_OBJECTS = \
+ examples/frc_pingpong.$(OBJEXT) examples/pingpong.$(OBJEXT)
+examples_ibv_frc_pingpong_OBJECTS = \
+ $(am_examples_ibv_frc_pingpong_OBJECTS)
+examples_ibv_frc_pingpong_DEPENDENCIES = \
+ $(top_builddir)/src/libibverbs.la
am_examples_ibv_rc_pingpong_OBJECTS = examples/rc_pingpong.$(OBJEXT) \
examples/pingpong.$(OBJEXT)
examples_ibv_rc_pingpong_OBJECTS = \
$(am_examples_ibv_rc_pingpong_OBJECTS)
examples_ibv_rc_pingpong_DEPENDENCIES = \
$(top_builddir)/src/libibverbs.la
+am_examples_ibv_shpd_pingpong_OBJECTS = \
+ examples/shpd_pingpong.$(OBJEXT) examples/pingpong.$(OBJEXT)
+examples_ibv_shpd_pingpong_OBJECTS = \
+ $(am_examples_ibv_shpd_pingpong_OBJECTS)
+examples_ibv_shpd_pingpong_DEPENDENCIES = \
+ $(top_builddir)/src/libibverbs.la
am_examples_ibv_srq_pingpong_OBJECTS = \
examples/srq_pingpong.$(OBJEXT) examples/pingpong.$(OBJEXT)
examples_ibv_srq_pingpong_OBJECTS = \
@@ -245,7 +257,9 @@
$(examples_ibv_asyncwatch_SOURCES) \
$(examples_ibv_devices_SOURCES) \
$(examples_ibv_devinfo_SOURCES) \
+ $(examples_ibv_frc_pingpong_SOURCES) \
$(examples_ibv_rc_pingpong_SOURCES) \
+ $(examples_ibv_shpd_pingpong_SOURCES) \
$(examples_ibv_srq_pingpong_SOURCES) \
$(examples_ibv_uc_pingpong_SOURCES) \
$(examples_ibv_ud_pingpong_SOURCES) \
@@ -254,7 +268,9 @@
$(examples_ibv_asyncwatch_SOURCES) \
$(examples_ibv_devices_SOURCES) \
$(examples_ibv_devinfo_SOURCES) \
+ $(examples_ibv_frc_pingpong_SOURCES) \
$(examples_ibv_rc_pingpong_SOURCES) \
+ $(examples_ibv_shpd_pingpong_SOURCES) \
$(examples_ibv_srq_pingpong_SOURCES) \
$(examples_ibv_uc_pingpong_SOURCES) \
$(examples_ibv_ud_pingpong_SOURCES) \
@@ -291,15 +307,6 @@
CTAGS = ctags
CSCOPE = cscope
AM_RECURSIVE_TARGETS = cscope
-am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
- $(srcdir)/libibverbs.spec.in $(top_srcdir)/config/compile \
- $(top_srcdir)/config/config.guess \
- $(top_srcdir)/config/config.sub $(top_srcdir)/config/depcomp \
- $(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \
- $(top_srcdir)/config/missing AUTHORS COPYING ChangeLog README \
- config/compile config/config.guess config/config.sub \
- config/depcomp config/install-sh config/ltmain.sh \
- config/missing
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
@@ -450,12 +457,16 @@
examples_ibv_devices_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_devinfo_SOURCES = examples/devinfo.c
examples_ibv_devinfo_LDADD = $(top_builddir)/src/libibverbs.la
+examples_ibv_frc_pingpong_SOURCES = examples/frc_pingpong.c examples/pingpong.c
+examples_ibv_frc_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_rc_pingpong_SOURCES = examples/rc_pingpong.c examples/pingpong.c
examples_ibv_rc_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_uc_pingpong_SOURCES = examples/uc_pingpong.c examples/pingpong.c
examples_ibv_uc_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_ud_pingpong_SOURCES = examples/ud_pingpong.c examples/pingpong.c
examples_ibv_ud_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
+examples_ibv_shpd_pingpong_SOURCES = examples/shpd_pingpong.c examples/pingpong.c
+examples_ibv_shpd_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_srq_pingpong_SOURCES = examples/srq_pingpong.c examples/pingpong.c
examples_ibv_srq_pingpong_LDADD = $(top_builddir)/src/libibverbs.la
examples_ibv_xsrq_pingpong_SOURCES = examples/xsrq_pingpong.c examples/pingpong.c
@@ -468,6 +479,7 @@
include/infiniband/sa-kern-abi.h include/infiniband/sa.h include/infiniband/marshall.h include/infiniband/ofa_solaris.h
man_MANS = man/ibv_asyncwatch.1 man/ibv_devices.1 man/ibv_devinfo.1 \
+ man/ibv_shpd_pingpong.1 \
man/ibv_rc_pingpong.1 man/ibv_uc_pingpong.1 man/ibv_ud_pingpong.1 \
man/ibv_srq_pingpong.1 man/ibv_alloc_pd.3 man/ibv_attach_mcast.3 \
man/ibv_create_ah.3 man/ibv_create_ah_from_wc.3 \
@@ -517,6 +529,7 @@
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -689,14 +702,26 @@
examples/ibv_devinfo$(EXEEXT): $(examples_ibv_devinfo_OBJECTS) $(examples_ibv_devinfo_DEPENDENCIES) $(EXTRA_examples_ibv_devinfo_DEPENDENCIES) examples/$(am__dirstamp)
@rm -f examples/ibv_devinfo$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(examples_ibv_devinfo_OBJECTS) $(examples_ibv_devinfo_LDADD) $(LIBS)
-examples/rc_pingpong.$(OBJEXT): examples/$(am__dirstamp) \
+examples/frc_pingpong.$(OBJEXT): examples/$(am__dirstamp) \
examples/$(DEPDIR)/$(am__dirstamp)
examples/pingpong.$(OBJEXT): examples/$(am__dirstamp) \
examples/$(DEPDIR)/$(am__dirstamp)
+examples/ibv_frc_pingpong$(EXEEXT): $(examples_ibv_frc_pingpong_OBJECTS) $(examples_ibv_frc_pingpong_DEPENDENCIES) $(EXTRA_examples_ibv_frc_pingpong_DEPENDENCIES) examples/$(am__dirstamp)
+ @rm -f examples/ibv_frc_pingpong$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(examples_ibv_frc_pingpong_OBJECTS) $(examples_ibv_frc_pingpong_LDADD) $(LIBS)
+examples/rc_pingpong.$(OBJEXT): examples/$(am__dirstamp) \
+ examples/$(DEPDIR)/$(am__dirstamp)
+
examples/ibv_rc_pingpong$(EXEEXT): $(examples_ibv_rc_pingpong_OBJECTS) $(examples_ibv_rc_pingpong_DEPENDENCIES) $(EXTRA_examples_ibv_rc_pingpong_DEPENDENCIES) examples/$(am__dirstamp)
@rm -f examples/ibv_rc_pingpong$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(examples_ibv_rc_pingpong_OBJECTS) $(examples_ibv_rc_pingpong_LDADD) $(LIBS)
+examples/shpd_pingpong.$(OBJEXT): examples/$(am__dirstamp) \
+ examples/$(DEPDIR)/$(am__dirstamp)
+
+examples/ibv_shpd_pingpong$(EXEEXT): $(examples_ibv_shpd_pingpong_OBJECTS) $(examples_ibv_shpd_pingpong_DEPENDENCIES) $(EXTRA_examples_ibv_shpd_pingpong_DEPENDENCIES) examples/$(am__dirstamp)
+ @rm -f examples/ibv_shpd_pingpong$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(examples_ibv_shpd_pingpong_OBJECTS) $(examples_ibv_shpd_pingpong_LDADD) $(LIBS)
examples/srq_pingpong.$(OBJEXT): examples/$(am__dirstamp) \
examples/$(DEPDIR)/$(am__dirstamp)
@@ -734,8 +759,10 @@
@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/asyncwatch.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/device_list.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/devinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/frc_pingpong.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/pingpong.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/rc_pingpong.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/shpd_pingpong.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/srq_pingpong.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/uc_pingpong.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@examples/$(DEPDIR)/ud_pingpong.Po@am__quote@
@@ -1081,15 +1108,15 @@
$(am__post_remove_distdir)
dist-tarZ: distdir
- @echo WARNING: "Support for distribution archives compressed with" \
- "legacy program 'compress' is deprecated." >&2
+ @echo WARNING: "Support for shar distribution archives is" \
+ "deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__post_remove_distdir)
dist-shar: distdir
- @echo WARNING: "Support for shar distribution archives is" \
- "deprecated." >&2
+ @echo WARNING: "Support for distribution archives compressed with" \
+ "legacy program 'compress' is deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__post_remove_distdir)
@@ -1125,17 +1152,17 @@
esac
chmod -R a-w $(distdir)
chmod u+w $(distdir)
- mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+ mkdir $(distdir)/_build $(distdir)/_inst
chmod a-w $(distdir)
test -d $(distdir)/_build || exit 0; \
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& am__cwd=`pwd` \
- && $(am__cd) $(distdir)/_build/sub \
- && ../../configure \
+ && $(am__cd) $(distdir)/_build \
+ && ../configure \
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
$(DISTCHECK_CONFIGURE_FLAGS) \
- --srcdir=../.. --prefix="$$dc_install_base" \
+ --srcdir=.. --prefix="$$dc_install_base" \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
@@ -1334,8 +1361,6 @@
uninstall-libibverbsincludeHEADERS uninstall-man \
uninstall-man1 uninstall-man3
-.PRECIOUS: Makefile
-
dist-hook: libibverbs.spec
cp libibverbs.spec $(distdir)
diff -r 688b7fd31600 examples/frc_pingpong.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/frc_pingpong.c Tue Nov 24 20:12:48 2015 -0800
@@ -0,0 +1,950 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <arpa/inet.h>
+#include <time.h>
+#include <errno.h>
+
+#include "pingpong.h"
+
+enum {
+ PINGPONG_RECV_WRID = 1,
+ PINGPONG_SEND_WRID = 2,
+};
+
+static int page_size;
+static int roffset = 0;
+static int soffset = 0;
+static long mr_calls_failed = 0;
+
+#define MAX_QUEUELEN 500
+
+struct pingpong_context {
+ struct ibv_context *context;
+ struct ibv_comp_channel *channel;
+ struct ibv_pd *pd;
+ struct ibv_mr *rmr[MAX_QUEUELEN];
+ struct ibv_mr *smr[MAX_QUEUELEN];
+ struct ibv_cq *cq;
+ struct ibv_qp *qp;
+ void *rbuf;
+ void *sbuf;
+ int size;
+ int rx_depth;
+ int rpending;
+ int spending;
+ struct ibv_port_attr portinfo;
+};
+
+struct pingpong_dest {
+ int lid;
+ int qpn;
+ int psn;
+ union ibv_gid gid;
+};
+
+static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn,
+ enum ibv_mtu mtu, int sl,
+ struct pingpong_dest *dest, int sgid_idx)
+{
+ struct ibv_qp_attr attr = {
+ .qp_state = IBV_QPS_RTR,
+ .path_mtu = mtu,
+ .dest_qp_num = dest->qpn,
+ .rq_psn = dest->psn,
+ .max_dest_rd_atomic = 1,
+ .min_rnr_timer = 12,
+ .ah_attr = {
+ .is_global = 0,
+ .dlid = dest->lid,
+ .sl = sl,
+ .src_path_bits = 0,
+ .port_num = port
+ }
+ };
+
+ if (dest->gid.global.interface_id) {
+ attr.ah_attr.is_global = 1;
+ attr.ah_attr.grh.hop_limit = 1;
+ attr.ah_attr.grh.dgid = dest->gid;
+ attr.ah_attr.grh.sgid_index = sgid_idx;
+ }
+ if (ibv_modify_qp(ctx->qp, &attr,
+ IBV_QP_STATE |
+ IBV_QP_AV |
+ IBV_QP_PATH_MTU |
+ IBV_QP_DEST_QPN |
+ IBV_QP_RQ_PSN |
+ IBV_QP_MAX_DEST_RD_ATOMIC |
+ IBV_QP_MIN_RNR_TIMER)) {
+ fprintf(stderr, "Failed to modify QP to RTR\n");
+ return 1;
+ }
+
+ attr.qp_state = IBV_QPS_RTS;
+ attr.timeout = 14;
+ attr.retry_cnt = 7;
+ attr.rnr_retry = 7;
+ attr.sq_psn = my_psn;
+ attr.max_rd_atomic = 1;
+ if (ibv_modify_qp(ctx->qp, &attr,
+ IBV_QP_STATE |
+ IBV_QP_TIMEOUT |
+ IBV_QP_RETRY_CNT |
+ IBV_QP_RNR_RETRY |
+ IBV_QP_SQ_PSN |
+ IBV_QP_MAX_QP_RD_ATOMIC)) {
+ fprintf(stderr, "Failed to modify QP to RTS\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port,
+ const struct pingpong_dest *my_dest)
+{
+ struct addrinfo *res, *t;
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM
+ };
+ char *service;
+ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"];
+ int n;
+ int sockfd = -1;
+ struct pingpong_dest *rem_dest = NULL;
+ char gid[33];
+
+ if (asprintf(&service, "%d", port) < 0)
+ return NULL;
+
+ n = getaddrinfo(servername, service, &hints, &res);
+
+ if (n < 0) {
+ fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port);
+ free(service);
+ return NULL;
+ }
+
+ for (t = res; t; t = t->ai_next) {
+ sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
+ if (sockfd >= 0) {
+ if (!connect(sockfd, t->ai_addr, t->ai_addrlen))
+ break;
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+
+ freeaddrinfo(res);
+ free(service);
+
+ if (sockfd < 0) {
+ fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port);
+ return NULL;
+ }
+
+ gid_to_wire_gid(&my_dest->gid, gid);
+ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid);
+ if (write(sockfd, msg, sizeof msg) != sizeof msg) {
+ fprintf(stderr, "Couldn't send local address\n");
+ goto out;
+ }
+
+ if (read(sockfd, msg, sizeof msg) != sizeof msg) {
+ perror("client read");
+ fprintf(stderr, "Couldn't read remote address\n");
+ goto out;
+ }
+
+ write(sockfd, "done", sizeof "done");
+
+ rem_dest = malloc(sizeof *rem_dest);
+ if (!rem_dest)
+ goto out;
+
+ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid);
+ wire_gid_to_gid(gid, &rem_dest->gid);
+
+out:
+ close(sockfd);
+ return rem_dest;
+}
+
+static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx,
+ int ib_port, enum ibv_mtu mtu,
+ int port, int sl,
+ const struct pingpong_dest *my_dest,
+ int sgid_idx)
+{
+ struct addrinfo *res, *t;
+ struct addrinfo hints = {
+ .ai_flags = AI_PASSIVE,
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM
+ };
+ char *service;
+ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"];
+ int n;
+ int sockfd = -1, connfd;
+ struct pingpong_dest *rem_dest = NULL;
+ char gid[33];
+
+ if (asprintf(&service, "%d", port) < 0)
+ return NULL;
+
+ n = getaddrinfo(NULL, service, &hints, &res);
+
+ if (n < 0) {
+ fprintf(stderr, "%s for port %d\n", gai_strerror(n), port);
+ free(service);
+ return NULL;
+ }
+
+ for (t = res; t; t = t->ai_next) {
+ sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
+ if (sockfd >= 0) {
+ n = 1;
+
+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n);
+
+ if (!bind(sockfd, t->ai_addr, t->ai_addrlen))
+ break;
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+
+ freeaddrinfo(res);
+ free(service);
+
+ if (sockfd < 0) {
+ fprintf(stderr, "Couldn't listen to port %d\n", port);
+ return NULL;
+ }
+
+ listen(sockfd, 1);
+ connfd = accept(sockfd, NULL, 0);
+ close(sockfd);
+ if (connfd < 0) {
+ fprintf(stderr, "accept() failed\n");
+ return NULL;
+ }
+
+ n = read(connfd, msg, sizeof msg);
+ if (n != sizeof msg) {
+ perror("server read");
+ fprintf(stderr, "%d/%d: Couldn't read remote address\n", n, (int) sizeof msg);
+ goto out;
+ }
+
+ rem_dest = malloc(sizeof *rem_dest);
+ if (!rem_dest)
+ goto out;
+
+ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid);
+ wire_gid_to_gid(gid, &rem_dest->gid);
+
+ if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest, sgid_idx)) {
+ fprintf(stderr, "Couldn't connect to remote QP\n");
+ free(rem_dest);
+ rem_dest = NULL;
+ goto out;
+ }
+
+
+ gid_to_wire_gid(&my_dest->gid, gid);
+ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid);
+ if (write(connfd, msg, sizeof msg) != sizeof msg) {
+ fprintf(stderr, "Couldn't send local address\n");
+ free(rem_dest);
+ rem_dest = NULL;
+ goto out;
+ }
+
+ read(connfd, msg, sizeof msg);
+
+out:
+ close(connfd);
+ return rem_dest;
+}
+
+static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
+ int rx_depth, int port,
+ int use_event, int is_server)
+{
+ struct pingpong_context *ctx;
+
+ ctx = calloc(1, sizeof *ctx);
+ if (!ctx)
+ return NULL;
+
+ ctx->size = size;
+ ctx->rx_depth = rx_depth;
+
+ ctx->rbuf = memalign(page_size, size * MAX_QUEUELEN);
+ ctx->sbuf = memalign(page_size, size * MAX_QUEUELEN);
+ if (!ctx->rbuf || !ctx->sbuf) {
+ fprintf(stderr, "Couldn't allocate work buf.\n");
+ return NULL;
+ }
+
+ memset(ctx->sbuf, 0x7b + is_server, size * 2);
+ memset(ctx->sbuf + size*2, 0xcc + is_server, size * 2);
+ ((char*)ctx->sbuf)[ctx->size * 4 + 1] = (char)0xab;
+
+ ctx->context = ibv_open_device(ib_dev);
+ if (!ctx->context) {
+ fprintf(stderr, "Couldn't get context for %s\n",
+ ibv_get_device_name(ib_dev));
+ return NULL;
+ }
+
+ if (use_event) {
+ ctx->channel = ibv_create_comp_channel(ctx->context);
+ if (!ctx->channel) {
+ fprintf(stderr, "Couldn't create completion channel\n");
+ return NULL;
+ }
+ } else
+ ctx->channel = NULL;
+
+ ctx->pd = ibv_alloc_pd(ctx->context);
+ if (!ctx->pd) {
+ fprintf(stderr, "Couldn't allocate PD\n");
+ return NULL;
+ }
+
+s_retry:
+ ctx->smr[0] = ibv_reg_mr_relaxed(ctx->pd, ctx->sbuf, size,
+ IBV_ACCESS_LOCAL_WRITE);
+ if (!ctx->smr[0]) {
+ mr_calls_failed++;
+ if (errno == EAGAIN) {
+ usleep(1);
+ goto s_retry;
+ }
+ fprintf(stderr, "Couldn't register MR\n");
+ return NULL;
+ }
+ printf("fmr:lkey = %x, rkey = %x for start=%p, len = %lu , access = %x\n",
+ ctx->smr[0]->lkey, ctx->smr[0]->rkey, ctx->sbuf, size,
+ IBV_ACCESS_LOCAL_WRITE);
+
+retry:
+ ctx->rmr[0] = ibv_reg_mr_relaxed(ctx->pd, ctx->rbuf, size,
+ IBV_ACCESS_LOCAL_WRITE);
+ if (!ctx->rmr[0]) {
+ mr_calls_failed++;
+ if (errno == EAGAIN) {
+ usleep(1);
+ goto retry;
+ }
+ fprintf(stderr, "Couldn't register MR\n");
+ return NULL;
+ }
+ printf("fmr:lkey = %x, rkey = %x for start=%p, len = %lu , access = %x\n",
+ ctx->rmr[0]->lkey, ctx->rmr[0]->rkey, ctx->rbuf, size,
+ IBV_ACCESS_LOCAL_WRITE);
+
+ ctx->cq = ibv_create_cq(ctx->context, rx_depth * 2 + 1, NULL,
+ ctx->channel, 0);
+ if (!ctx->cq) {
+ fprintf(stderr, "Couldn't create CQ\n");
+ return NULL;
+ }
+
+ {
+ struct ibv_qp_init_attr attr = {
+ .send_cq = ctx->cq,
+ .recv_cq = ctx->cq,
+ .cap = {
+ .max_send_wr = rx_depth,
+ .max_recv_wr = rx_depth,
+ .max_send_sge = 1,
+ .max_recv_sge = 1
+ },
+ .qp_type = IBV_QPT_RC
+ };
+
+ ctx->qp = ibv_create_qp(ctx->pd, &attr);
+ if (!ctx->qp) {
+ fprintf(stderr, "Couldn't create QP\n");
+ return NULL;
+ }
+ }
+
+ {
+ struct ibv_qp_attr attr = {
+ .qp_state = IBV_QPS_INIT,
+ .pkey_index = 0,
+ .port_num = port,
+ .qp_access_flags = 0
+ };
+
+ if (ibv_modify_qp(ctx->qp, &attr,
+ IBV_QP_STATE |
+ IBV_QP_PKEY_INDEX |
+ IBV_QP_PORT |
+ IBV_QP_ACCESS_FLAGS)) {
+ fprintf(stderr, "Failed to modify QP to INIT\n");
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+int pp_close_ctx(struct pingpong_context *ctx)
+{
+ int i = 0;
+ if (ibv_destroy_qp(ctx->qp)) {
+ fprintf(stderr, "Couldn't destroy QP\n");
+ return 1;
+ }
+
+ if (ibv_destroy_cq(ctx->cq)) {
+ fprintf(stderr, "Couldn't destroy CQ\n");
+ return 1;
+ }
+
+ for (i = 0; i < MAX_QUEUELEN; i++) {
+ if (ctx->smr[i] && ibv_dereg_mr_relaxed(ctx->smr[i])) {
+ fprintf(stderr, "Couldn't deregister MR\n");
+ return 1;
+ }
+ if (ctx->rmr[i] && ibv_dereg_mr_relaxed(ctx->rmr[i])) {
+ fprintf(stderr, "Couldn't deregister MR\n");
+ return 1;
+ }
+ }
+
+ if (ibv_dealloc_pd(ctx->pd)) {
+ fprintf(stderr, "Couldn't deallocate PD\n");
+ return 1;
+ }
+
+ if (ctx->channel) {
+ if (ibv_destroy_comp_channel(ctx->channel)) {
+ fprintf(stderr, "Couldn't destroy completion channel\n");
+ return 1;
+ }
+ }
+
+ if (ibv_close_device(ctx->context)) {
+ fprintf(stderr, "Couldn't release context\n");
+ return 1;
+ }
+
+ if (*(char*)ctx->rbuf == 0x7b || *(char*)ctx->rbuf == 0x7c) {
+ char is_server = *(char*)ctx->rbuf - (char)0x7b;
+ char *buf1 = ctx->rbuf;
+ char *buf2 = ctx->rbuf + 2 * ctx->size;
+ for (i = 0 ; i < ctx->size * 2; i++) {
+ if (buf1[i] != (0x7b + is_server) ) {
+ fprintf(stderr, "Data corruption at %d - %x\n", i, buf1[i]);
+ break;
+ }
+ if ((char)buf2[i] != (char)(0xcc + is_server)) {
+ fprintf(stderr, "Data corruption at %d - %x\n", 2 * ctx->size + i, buf2[i]);
+ break;
+ }
+ }
+ }
+
+ if ((char)((char*)ctx->rbuf)[ctx->size * 4 + 1] != (char)0xab)
+ fprintf(stderr, "Data corruption at %d - %x\n", ctx->size * 4 + 1, (char)((char*)ctx->rbuf)[ctx->size * 4 + 1]);
+
+ free(ctx->rbuf);
+ free(ctx->sbuf);
+ free(ctx);
+
+ return 0;
+}
+
+static int pp_post_recv(struct pingpong_context *ctx, int n)
+{
+
+ if (ctx->rmr[roffset] && ibv_dereg_mr_relaxed(ctx->rmr[roffset])) {
+ fprintf(stderr, "Couldn't unregister MT\n");
+ return -1;
+ }
+retry:
+ ctx->rmr[roffset]= ibv_reg_mr_relaxed(ctx->pd, ctx->rbuf + roffset*ctx->size,
+ ctx->size , IBV_ACCESS_LOCAL_WRITE);
+ if (!ctx->rmr[roffset]) {
+ mr_calls_failed++;
+ if (errno == EAGAIN) {
+ usleep(1);
+ goto retry;
+ }
+ fprintf(stderr, "Couldn't register MR\n");
+ return -1;
+ }
+ {
+ struct ibv_sge list = {
+ .addr = (uintptr_t) ctx->rbuf + roffset * ctx->size,
+ .length = ctx->size,
+ .lkey = ctx->rmr[roffset]->lkey
+ };
+ struct ibv_recv_wr wr = {
+ .wr_id = PINGPONG_RECV_WRID,
+ .sg_list = &list,
+ .num_sge = 1,
+ };
+ struct ibv_recv_wr *bad_wr;
+ int i;
+
+ roffset++;
+ if (roffset >= MAX_QUEUELEN)
+ roffset = 0;
+
+ for (i = 0; i < n; ++i)
+ if (ibv_post_recv(ctx->qp, &wr, &bad_wr))
+ break;
+
+ return i;
+ }
+}
+
+static int pp_post_send(struct pingpong_context *ctx)
+{
+ if (ctx->smr[soffset] && ibv_dereg_mr_relaxed(ctx->smr[soffset])) {
+ fprintf(stderr, "Couldn't unregister MT\n");
+ return -1;
+ }
+retry:
+ ctx->smr[soffset] = ibv_reg_mr_relaxed(ctx->pd, ctx->sbuf + soffset * ctx->size,
+ ctx->size, IBV_ACCESS_LOCAL_WRITE);
+ if (!ctx->smr[soffset]) {
+ mr_calls_failed++;
+ if (errno == EAGAIN) {
+ usleep(1);
+ goto retry;
+ }
+ fprintf(stderr, "Couldn't register MR\n");
+ return -1;
+ }
+
+ {
+ struct ibv_sge list = {
+ .addr = (uintptr_t) ctx->sbuf + soffset * ctx->size,
+ .length = ctx->size,
+ .lkey = ctx->smr[soffset]->lkey
+ };
+ struct ibv_send_wr wr = {
+ .wr_id = PINGPONG_SEND_WRID,
+ .sg_list = &list,
+ .num_sge = 1,
+ .opcode = IBV_WR_SEND,
+ .send_flags = IBV_SEND_SIGNALED,
+ };
+ struct ibv_send_wr *bad_wr;
+
+ soffset++;
+ if (soffset >= MAX_QUEUELEN)
+ soffset = 0;
+
+ return ibv_post_send(ctx->qp, &wr, &bad_wr);
+ }
+}
+
+static void usage(const char *argv0)
+{
+ printf("Usage:\n");
+ printf(" %s start a server and wait for connection\n", argv0);
+ printf(" %s <host> connect to server at <host>\n", argv0);
+ printf("\n");
+ printf("Options:\n");
+ printf(" -p, --port=<port> listen on/connect to port <port> (default 18515)\n");
+ printf(" -d, --ib-dev=<dev> use IB device <dev> (default first device found)\n");
+ printf(" -i, --ib-port=<port> use port <port> of IB device (default 1)\n");
+ printf(" -s, --size=<size> size of message to exchange (default 4096)\n");
+ printf(" -m, --mtu=<size> path MTU (default 1024)\n");
+ printf(" -r, --rx-depth=<dep> number of receives to post at a time (default 500)\n");
+ printf(" -n, --iters=<iters> number of exchanges (default 1000)\n");
+ printf(" -l, --sl=<sl> service level value\n");
+ printf(" -e, --events sleep on CQ events (default poll)\n");
+ printf(" -g, --gid-idx=<gid index> local port gid index\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct ibv_device **dev_list;
+ struct ibv_device *ib_dev;
+ struct pingpong_context *ctx;
+ struct pingpong_dest my_dest;
+ struct pingpong_dest *rem_dest;
+ struct timeval start, end;
+ char *ib_devname = NULL;
+ char *servername = NULL;
+ int port = 18515;
+ int ib_port = 1;
+ int size = 4096;
+ enum ibv_mtu mtu = IBV_MTU_1024;
+ int rx_depth = 200;
+ int iters = 1000;
+ int use_event = 0;
+ int routs;
+ int rcnt, scnt;
+ int num_cq_events = 0;
+ int sl = 0;
+ int gidx = -1;
+ char gid[33];
+
+ srand48(getpid() * time(NULL));
+
+ while (1) {
+ int c;
+
+ static struct option long_options[] = {
+ { .name = "port", .has_arg = 1, .val = 'p' },
+ { .name = "ib-dev", .has_arg = 1, .val = 'd' },
+ { .name = "ib-port", .has_arg = 1, .val = 'i' },
+ { .name = "size", .has_arg = 1, .val = 's' },
+ { .name = "mtu", .has_arg = 1, .val = 'm' },
+ { .name = "rx-depth", .has_arg = 1, .val = 'r' },
+ { .name = "iters", .has_arg = 1, .val = 'n' },
+ { .name = "sl", .has_arg = 1, .val = 'l' },
+ { .name = "events", .has_arg = 0, .val = 'e' },
+ { .name = "gid-idx", .has_arg = 1, .val = 'g' },
+ { 0 }
+ };
+
+ c = getopt_long(argc, argv, "p:d:i:s:m:r:n:l:eg:", long_options, NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'p':
+ port = strtol(optarg, NULL, 0);
+ if (port < 0 || port > 65535) {
+ usage(argv[0]);
+ return 1;
+ }
+ break;
+
+ case 'd':
+ ib_devname = strdupa(optarg);
+ break;
+
+ case 'i':
+ ib_port = strtol(optarg, NULL, 0);
+ if (ib_port < 0) {
+ usage(argv[0]);
+ return 1;
+ }
+ break;
+
+ case 's':
+ size = strtol(optarg, NULL, 0);
+ break;
+
+ case 'm':
+ mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0));
+ if (mtu < 0) {
+ usage(argv[0]);
+ return 1;
+ }
+ break;
+
+ case 'r':
+ rx_depth = strtol(optarg, NULL, 0);
+ break;
+
+ case 'n':
+ iters = strtol(optarg, NULL, 0);
+ break;
+
+ case 'l':
+ sl = strtol(optarg, NULL, 0);
+ break;
+
+ case 'e':
+ ++use_event;
+ break;
+
+ case 'g':
+ gidx = strtol(optarg, NULL, 0);
+ break;
+
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ if (optind == argc - 1)
+ servername = strdupa(argv[optind]);
+ else if (optind < argc) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ page_size = sysconf(_SC_PAGESIZE);
+
+ dev_list = ibv_get_device_list(NULL);
+ if (!dev_list) {
+ perror("Failed to get IB devices list");
+ return 1;
+ }
+
+ if (!ib_devname) {
+ ib_dev = *dev_list;
+ if (!ib_dev) {
+ fprintf(stderr, "No IB devices found\n");
+ return 1;
+ }
+ } else {
+ int i;
+ for (i = 0; dev_list[i]; ++i)
+ if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname))
+ break;
+ ib_dev = dev_list[i];
+ if (!ib_dev) {
+ fprintf(stderr, "IB device %s not found\n", ib_devname);
+ return 1;
+ }
+ }
+
+ ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event, !servername);
+ if (!ctx)
+ return 1;
+
+ {
+ int i = 0;
+ for (i = 0; i < ctx->rx_depth; i++) {
+ routs += pp_post_recv(ctx, 1);
+ }
+ }
+ if (routs < ctx->rx_depth) {
+ fprintf(stderr, "Couldn't post receive (%d)\n", routs);
+ return 1;
+ }
+
+ if (use_event)
+ if (ibv_req_notify_cq(ctx->cq, 0)) {
+ fprintf(stderr, "Couldn't request CQ notification\n");
+ return 1;
+ }
+
+
+ if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) {
+ fprintf(stderr, "Couldn't get port info\n");
+ return 1;
+ }
+
+ my_dest.lid = ctx->portinfo.lid;
+ if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest.lid) {
+ fprintf(stderr, "Couldn't get local LID\n");
+ return 1;
+ }
+
+ if (gidx >= 0) {
+ if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) {
+ fprintf(stderr, "Could not get local gid for gid index %d\n", gidx);
+ return 1;
+ }
+ } else
+ memset(&my_dest.gid, 0, sizeof my_dest.gid);
+
+ my_dest.qpn = ctx->qp->qp_num;
+ my_dest.psn = lrand48() & 0xffffff;
+ inet_ntop(AF_INET6, &my_dest.gid, gid, sizeof gid);
+ printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n",
+ my_dest.lid, my_dest.qpn, my_dest.psn, gid);
+
+
+ if (servername)
+ rem_dest = pp_client_exch_dest(servername, port, &my_dest);
+ else
+ rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest, gidx);
+
+ if (!rem_dest)
+ return 1;
+
+ inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid);
+ printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n",
+ rem_dest->lid, rem_dest->qpn, rem_dest->psn, gid);
+
+ if (servername)
+ if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest, gidx))
+ return 1;
+
+ ctx->rpending = ctx->rx_depth;
+
+ if (servername) {
+ while (ctx->spending < ctx->rx_depth) {
+ ctx->spending++;
+ if (pp_post_send(ctx)) {
+ fprintf(stderr, "Couldn't post send\n");
+ return 1;
+ }
+ }
+ }
+
+ if (gettimeofday(&start, NULL)) {
+ perror("gettimeofday");
+ return 1;
+ }
+
+ rcnt = scnt = 0;
+ while (rcnt < iters || scnt < iters) {
+ if (use_event) {
+ struct ibv_cq *ev_cq;
+ void *ev_ctx;
+
+ if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) {
+ fprintf(stderr, "Failed to get cq_event\n");
+ return 1;
+ }
+
+ ++num_cq_events;
+
+ if (ev_cq != ctx->cq) {
+ fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq);
+ return 1;
+ }
+
+ if (ibv_req_notify_cq(ctx->cq, 0)) {
+ fprintf(stderr, "Couldn't request CQ notification\n");
+ return 1;
+ }
+ }
+
+ {
+ struct ibv_wc wc[100];
+ int ne, i;
+
+ do {
+ ne = ibv_poll_cq(ctx->cq, 100, wc);
+ if (ne < 0) {
+ fprintf(stderr, "poll CQ failed %d\n", ne);
+ return 1;
+ }
+
+ } while (!use_event && ne < 1);
+
+ for (i = 0; i < ne; ++i) {
+ if (wc[i].status != IBV_WC_SUCCESS) {
+ fprintf(stderr, "Failed status %s (%d[%d]) for wr_id %d(scnt %d, rcnt %d, i %d)\n",
+ ibv_wc_status_str(wc[i].status),
+ wc[i].status,wc[i].vendor_err, (int) wc[i].wr_id, scnt, rcnt, i);
+ return 1;
+ }
+
+ switch ((int) wc[i].wr_id) {
+ case PINGPONG_SEND_WRID:
+ ctx->spending--;
+ ++scnt;
+ break;
+
+ case PINGPONG_RECV_WRID:
+ ctx->rpending--;
+ --routs ;
+ routs += pp_post_recv(ctx, 1);
+ if (routs < ctx->rx_depth) {
+ fprintf(stderr,
+ "Couldn't post receive (%d)\n",
+ routs);
+ return 1;
+ }
+ ctx->rpending++;
+
+ ++rcnt;
+ break;
+
+ default:
+ fprintf(stderr, "Completion for unknown wr_id %d\n",
+ (int) wc[i].wr_id);
+ return 1;
+ }
+
+ if ((ctx->spending + scnt) < iters) {
+ int j =0;
+ int count = iters - (ctx->spending + scnt);
+ count = (count > (ctx->rx_depth - ctx->spending)) ?
+ ctx->rx_depth - ctx->spending : count;
+ for (j = 0; j < count; j++) {
+ if (pp_post_send(ctx)) {
+ fprintf(stderr, "Couldn't post send %d, count %d\n", i, count);
+ return 1;
+ }
+ }
+ ctx->spending += count;
+ }
+ }
+ }
+ }
+
+ if (gettimeofday(&end, NULL)) {
+ perror("gettimeofday");
+ return 1;
+ }
+
+ {
+ float usec = (end.tv_sec - start.tv_sec) * 1000000 +
+ (end.tv_usec - start.tv_usec);
+ long long bytes = (long long) size * iters * 2;
+
+ printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n",
+ bytes, usec / 1000000., bytes * 8. / usec);
+ printf("%d iters in %.2f seconds = %.2f usec/iter\n",
+ iters, usec / 1000000., usec / iters);
+ }
+ printf(" %lld reg_mrs failed\n", mr_calls_failed);
+
+ ibv_ack_cq_events(ctx->cq, num_cq_events);
+
+ if (pp_close_ctx(ctx))
+ return 1;
+
+ ibv_free_device_list(dev_list);
+ free(rem_dest);
+
+ return 0;
+}
diff -r 688b7fd31600 examples/shpd_pingpong.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/shpd_pingpong.c Tue Nov 24 20:12:48 2015 -0800
@@ -0,0 +1,960 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <arpa/inet.h>
+#include <time.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <errno.h>
+
+#include "pingpong.h"
+
+enum {
+ PINGPONG_RECV_WRID = 1,
+ PINGPONG_SEND_WRID = 2,
+};
+
+static int page_size;
+
+struct ppshm {
+ void *shmaddr;
+ struct ibv_shpd shpd;
+ struct ibv_mr mr;
+ volatile int status;
+ char buf[1];
+};
+
+struct pingpong_context {
+ struct ibv_context *context;
+ struct ibv_comp_channel *channel;
+ struct ibv_pd *pd;
+ struct ibv_mr *mr;
+ struct ibv_cq *cq;
+ struct ibv_qp *qp;
+ void *buf;
+ int size;
+ int rx_depth;
+ int pending;
+ struct ibv_port_attr portinfo;
+ struct ibv_shpd shpd;
+ int is_server;
+ key_t key;
+ int shmsize;
+ int shmid;
+ uintptr_t shmoffset;
+ struct ppshm *shm;
+};
+
+struct pingpong_dest {
+ int lid;
+ int qpn;
+ int psn;
+ union ibv_gid gid;
+};
+
+static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn,
+ enum ibv_mtu mtu, int sl,
+ struct pingpong_dest *dest, int sgid_idx)
+{
+ struct ibv_qp_attr attr = {
+ .qp_state = IBV_QPS_RTR,
+ .path_mtu = mtu,
+ .dest_qp_num = dest->qpn,
+ .rq_psn = dest->psn,
+ .max_dest_rd_atomic = 1,
+ .min_rnr_timer = 12,
+ .ah_attr = {
+ .is_global = 0,
+ .dlid = dest->lid,
+ .sl = sl,
+ .src_path_bits = 0,
+ .port_num = port
+ }
+ };
+
+ if (dest->gid.global.interface_id) {
+ attr.ah_attr.is_global = 1;
+ attr.ah_attr.grh.hop_limit = 1;
+ attr.ah_attr.grh.dgid = dest->gid;
+ attr.ah_attr.grh.sgid_index = sgid_idx;
+ }
+ if (ibv_modify_qp(ctx->qp, &attr,
+ IBV_QP_STATE |
+ IBV_QP_AV |
+ IBV_QP_PATH_MTU |
+ IBV_QP_DEST_QPN |
+ IBV_QP_RQ_PSN |
+ IBV_QP_MAX_DEST_RD_ATOMIC |
+ IBV_QP_MIN_RNR_TIMER)) {
+ fprintf(stderr, "Failed to modify QP to RTR\n");
+ return 1;
+ }
+
+ attr.qp_state = IBV_QPS_RTS;
+ attr.timeout = 14;
+ attr.retry_cnt = 7;
+ attr.rnr_retry = 7;
+ attr.sq_psn = my_psn;
+ attr.max_rd_atomic = 1;
+ if (ibv_modify_qp(ctx->qp, &attr,
+ IBV_QP_STATE |
+ IBV_QP_TIMEOUT |
+ IBV_QP_RETRY_CNT |
+ IBV_QP_RNR_RETRY |
+ IBV_QP_SQ_PSN |
+ IBV_QP_MAX_QP_RD_ATOMIC)) {
+ fprintf(stderr, "Failed to modify QP to RTS\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port,
+ const struct pingpong_dest *my_dest)
+{
+ struct addrinfo *res, *t;
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM
+ };
+ char *service;
+ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"];
+ int n;
+ int sockfd = -1;
+ struct pingpong_dest *rem_dest = NULL;
+ char gid[33];
+
+ if (asprintf(&service, "%d", port) < 0)
+ return NULL;
+
+ n = getaddrinfo(servername, service, &hints, &res);
+
+ if (n < 0) {
+ fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port);
+ free(service);
+ return NULL;
+ }
+
+ for (t = res; t; t = t->ai_next) {
+ sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
+ if (sockfd >= 0) {
+ if (!connect(sockfd, t->ai_addr, t->ai_addrlen))
+ break;
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+
+ freeaddrinfo(res);
+ free(service);
+
+ if (sockfd < 0) {
+ fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port);
+ return NULL;
+ }
+
+ gid_to_wire_gid(&my_dest->gid, gid);
+ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid);
+ if (write(sockfd, msg, sizeof msg) != sizeof msg) {
+ fprintf(stderr, "Couldn't send local address\n");
+ goto out;
+ }
+
+ if (read(sockfd, msg, sizeof msg) != sizeof msg) {
+ perror("client read");
+ fprintf(stderr, "Couldn't read remote address\n");
+ goto out;
+ }
+
+ write(sockfd, "done", sizeof "done");
+
+ rem_dest = malloc(sizeof *rem_dest);
+ if (!rem_dest)
+ goto out;
+
+ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid);
+ wire_gid_to_gid(gid, &rem_dest->gid);
+
+out:
+ close(sockfd);
+ return rem_dest;
+}
+
+static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx,
+ int ib_port, enum ibv_mtu mtu,
+ int port, int sl,
+ const struct pingpong_dest *my_dest,
+ int sgid_idx)
+{
+ struct addrinfo *res, *t;
+ struct addrinfo hints = {
+ .ai_flags = AI_PASSIVE,
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM
+ };
+ char *service;
+ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"];
+ int n;
+ int sockfd = -1, connfd;
+ struct pingpong_dest *rem_dest = NULL;
+ char gid[33];
+
+ if (asprintf(&service, "%d", port) < 0)
+ return NULL;
+
+ n = getaddrinfo(NULL, service, &hints, &res);
+
+ if (n < 0) {
+ fprintf(stderr, "%s for port %d\n", gai_strerror(n), port);
+ free(service);
+ return NULL;
+ }
+
+ for (t = res; t; t = t->ai_next) {
+ sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
+ if (sockfd >= 0) {
+ n = 1;
+
+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n);
+
+ if (!bind(sockfd, t->ai_addr, t->ai_addrlen))
+ break;
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+
+ freeaddrinfo(res);
+ free(service);
+
+ if (sockfd < 0) {
+ fprintf(stderr, "Couldn't listen to port %d\n", port);
+ return NULL;
+ }
+
+ listen(sockfd, 1);
+ connfd = accept(sockfd, NULL, 0);
+ close(sockfd);
+ if (connfd < 0) {
+ fprintf(stderr, "accept() failed\n");
+ return NULL;
+ }
+
+ n = read(connfd, msg, sizeof msg);
+ if (n != sizeof msg) {
+ perror("server read");
+ fprintf(stderr, "%d/%d: Couldn't read remote address\n", n, (int) sizeof msg);
+ goto out;
+ }
+
+ rem_dest = malloc(sizeof *rem_dest);
+ if (!rem_dest)
+ goto out;
+
+ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid);
+ wire_gid_to_gid(gid, &rem_dest->gid);
+
+ if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest, sgid_idx)) {
+ fprintf(stderr, "Couldn't connect to remote QP\n");
+ free(rem_dest);
+ rem_dest = NULL;
+ goto out;
+ }
+
+
+ gid_to_wire_gid(&my_dest->gid, gid);
+ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid);
+ if (write(connfd, msg, sizeof msg) != sizeof msg) {
+ fprintf(stderr, "Couldn't send local address\n");
+ free(rem_dest);
+ rem_dest = NULL;
+ goto out;
+ }
+
+ read(connfd, msg, sizeof msg);
+
+out:
+ close(connfd);
+ return rem_dest;
+}
+
+static int pp_setup_shm(struct pingpong_context *ctx)
+{
+ ctx->shmid = shmget(ctx->key, ctx->shmsize, IPC_CREAT|IPC_EXCL|0666);
+ if (ctx->shmid == -1) {
+ fprintf(stderr, "shm with id %d already exists\n", ctx->key);
+ return 1;
+ }
+
+ ctx->shm = shmat(ctx->shmid, NULL, 0);
+ if (ctx->shm == (void *)-1) {
+ fprintf(stderr, "attach failed\n");
+ return 1;
+ }
+
+ ctx->shm->status = 0;
+ return 0;
+}
+
+static int pp_waitfor_shm(struct pingpong_context *ctx)
+{
+retry:
+ ctx->shmid = shmget(ctx->key, ctx->shmsize, 0666);
+ if (ctx->shmid == -1) {
+ sleep(1);
+ goto retry;
+ }
+ ctx->shm = shmat(ctx->shmid, NULL, 0);
+ if (ctx->shm == (void *)-1) {
+ fprintf(stderr, "attach failed\n");
+ return 1;
+ }
+
+ /* wait for status 2 */
+
+ while (ctx->shm->status == 0)
+ sleep(1);
+
+ if (ctx->shm->status == 1)
+ return 1;
+
+ return 0;
+}
+
+static int pp_delete_shm(struct pingpong_context *ctx)
+{
+ if (shmdt(ctx->shm)) {
+ fprintf(stderr, "Couldn't detach shm\n");
+ return 1;
+ }
+
+ if (ctx->is_server)
+ shmctl(ctx->shmid, IPC_RMID, 0);
+
+ return 0;
+}
+
+static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
+ int rx_depth, int port,
+ int use_event, key_t key, int is_server)
+{
+ struct pingpong_context *ctx;
+ uint64_t mypass = 1234;
+
+ ctx = calloc(1, sizeof *ctx);
+ if (!ctx)
+ return NULL;
+
+ ctx->size = size;
+ ctx->rx_depth = rx_depth;
+ ctx->is_server = is_server;
+ ctx->key = key;
+ ctx->shmsize = sizeof(*(ctx->shm)) + ctx->size * 2 + page_size * 2;
+ ctx->shmoffset = 0;
+
+ ctx->context = ibv_open_device(ib_dev);
+ if (!ctx->context) {
+ fprintf(stderr, "Couldn't get context for %s\n",
+ ibv_get_device_name(ib_dev));
+ return NULL;
+ }
+
+ if (use_event) {
+ ctx->channel = ibv_create_comp_channel(ctx->context);
+ if (!ctx->channel) {
+ fprintf(stderr, "Couldn't create completion channel\n");
+ return NULL;
+ }
+ } else
+ ctx->channel = NULL;
+
+ if (is_server) {
+ struct ibv_shpd *shpd;
+ ctx->pd = ibv_alloc_pd(ctx->context);
+ if (!ctx->pd) {
+ fprintf(stderr, "Couldn't allocate PD\n");
+ return NULL;
+ }
+
+ /* mark the pd as shareable & get shpd info */
+ shpd = ibv_alloc_shpd(ctx->pd, mypass, &ctx->shpd);
+ if (!shpd) {
+ fprintf(stderr, "Couldn't share PD : errno %d\n", errno);
+ return NULL;
+ }
+
+ if (pp_setup_shm(ctx))
+ return NULL;
+
+#define PAGE_ALIGN(addr, page) (uintptr_t)(((uintptr_t)addr + page - 1) \
+ & ~(page - 1))
+
+ /* use shared memory are as buffer */
+ ctx->buf = (char *)PAGE_ALIGN(ctx->shm->buf, page_size);
+
+ ctx->mr = ibv_reg_mr(ctx->pd, ctx->shm, ctx->shmsize, IBV_ACCESS_LOCAL_WRITE);
+ if (!ctx->mr) {
+ fprintf(stderr, "Couldn't register MR\n");
+ ctx->shm->status = 1;
+ return NULL;
+ }
+
+ ctx->shm->shpd = ctx->shpd;
+ ctx->shm->mr = *ctx->mr;
+ ctx->shm->shmaddr = ctx->shm;
+
+ /* all details initialized ready to go */
+ ctx->shm->status = 2;
+ } else {
+ if (pp_waitfor_shm(ctx)) {
+ fprintf(stderr, "Couldn't get shm working\n");
+ return NULL;
+ }
+
+ ctx->shpd = ctx->shm->shpd;
+ /* create pd from shared pd information we have */
+ ctx->pd = ibv_share_pd(ctx->context, &ctx->shpd, mypass);
+
+ /* NOTE: some parts of ibv_mr struct is invalid in client process.
+ only rkey & lkey is relevant
+ */
+ ctx->mr = &ctx->shm->mr;
+
+ /* the memory address at which shm is mapped in the client may not be same
+ as that in server. All WR to HCA should give local VA's w.r.t server's
+ shared memory address
+ */
+ ctx->shmoffset = (uintptr_t)(ctx->shm->shmaddr) - (uintptr_t)ctx->shm;
+ ctx->buf = (char *)PAGE_ALIGN(ctx->shm->buf, page_size)
+ + PAGE_ALIGN(size, page_size);
+ }
+
+ memset(ctx->buf, 0x7b + is_server, size);
+
+ ctx->cq = ibv_create_cq(ctx->context, rx_depth + 1, NULL,
+ ctx->channel, 0);
+ if (!ctx->cq) {
+ fprintf(stderr, "Couldn't create CQ\n");
+ return NULL;
+ }
+
+ {
+ struct ibv_qp_init_attr attr = {
+ .send_cq = ctx->cq,
+ .recv_cq = ctx->cq,
+ .cap = {
+ .max_send_wr = 1,
+ .max_recv_wr = rx_depth,
+ .max_send_sge = 1,
+ .max_recv_sge = 1
+ },
+ .qp_type = IBV_QPT_RC
+ };
+
+ ctx->qp = ibv_create_qp(ctx->pd, &attr);
+ if (!ctx->qp) {
+ fprintf(stderr, "Couldn't create QP\n");
+ return NULL;
+ }
+ }
+
+ {
+ struct ibv_qp_attr attr = {
+ .qp_state = IBV_QPS_INIT,
+ .pkey_index = 0,
+ .port_num = port,
+ .qp_access_flags = 0
+ };
+
+ if (ibv_modify_qp(ctx->qp, &attr,
+ IBV_QP_STATE |
+ IBV_QP_PKEY_INDEX |
+ IBV_QP_PORT |
+ IBV_QP_ACCESS_FLAGS)) {
+ fprintf(stderr, "Failed to modify QP to INIT\n");
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+int pp_close_ctx(struct pingpong_context *ctx)
+{
+ if (ibv_destroy_qp(ctx->qp)) {
+ fprintf(stderr, "Couldn't destroy QP\n");
+ return 1;
+ }
+
+ if (ibv_destroy_cq(ctx->cq)) {
+ fprintf(stderr, "Couldn't destroy CQ\n");
+ return 1;
+ }
+
+ if (ctx->is_server) {
+ if (ibv_dereg_mr(ctx->mr)) {
+ fprintf(stderr, "Couldn't deregister MR\n");
+ return 1;
+ }
+ }
+
+ if (pp_delete_shm(ctx)) {
+ fprintf(stderr, "couldn't destroy shared memory\n");
+ return 1;
+ }
+
+ if (ibv_dealloc_pd(ctx->pd)) {
+ fprintf(stderr, "Couldn't deallocate PD\n");
+ return 1;
+ }
+
+ if (ctx->channel) {
+ if (ibv_destroy_comp_channel(ctx->channel)) {
+ fprintf(stderr, "Couldn't destroy completion channel\n");
+ return 1;
+ }
+ }
+
+ if (ibv_close_device(ctx->context)) {
+ fprintf(stderr, "Couldn't release context\n");
+ return 1;
+ }
+
+ free(ctx);
+
+ return 0;
+}
+
+static int pp_post_recv(struct pingpong_context *ctx, int n)
+{
+ struct ibv_sge list = {
+ .addr = (uintptr_t) ctx->buf + ctx->shmoffset,
+ .length = ctx->size,
+ .lkey = ctx->mr->lkey
+ };
+ struct ibv_recv_wr wr = {
+ .wr_id = PINGPONG_RECV_WRID,
+ .sg_list = &list,
+ .num_sge = 1,
+ };
+ struct ibv_recv_wr *bad_wr;
+ int i;
+
+ for (i = 0; i < n; ++i)
+ if (ibv_post_recv(ctx->qp, &wr, &bad_wr))
+ break;
+
+ return i;
+}
+
+static int pp_post_send(struct pingpong_context *ctx)
+{
+ struct ibv_sge list = {
+ .addr = (uintptr_t) ctx->buf + ctx->shmoffset,
+ .length = ctx->size,
+ .lkey = ctx->mr->lkey
+ };
+ struct ibv_send_wr wr = {
+ .wr_id = PINGPONG_SEND_WRID,
+ .sg_list = &list,
+ .num_sge = 1,
+ .opcode = IBV_WR_SEND,
+ .send_flags = IBV_SEND_SIGNALED,
+ };
+ struct ibv_send_wr *bad_wr;
+
+ return ibv_post_send(ctx->qp, &wr, &bad_wr);
+}
+
+static void usage(const char *argv0)
+{
+ printf("Usage:\n");
+ printf(" %s start a server and wait for connection\n", argv0);
+ printf(" %s <host> connect to server at <host>\n", argv0);
+ printf("\n");
+ printf("Options:\n");
+ printf(" -p, --port=<port> listen on/connect to port <port> (default 18515)\n");
+ printf(" -d, --ib-dev=<dev> use IB device <dev> (default first device found)\n");
+ printf(" -i, --ib-port=<port> use port <port> of IB device (default 1)\n");
+ printf(" -s, --size=<size> size of message to exchange (default 4096)\n");
+ printf(" -m, --mtu=<size> path MTU (default 1024)\n");
+ printf(" -r, --rx-depth=<dep> number of receives to post at a time (default 500)\n");
+ printf(" -n, --iters=<iters> number of exchanges (default 1000)\n");
+ printf(" -l, --sl=<sl> service level value\n");
+ printf(" -e, --events sleep on CQ events (default poll)\n");
+ printf(" -g, --gid-idx=<gid index> local port gid index\n");
+ printf(" -S, --shm-key=<shm key> shared memory key for the test (default 18515)\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct ibv_device **dev_list;
+ struct ibv_device *ib_dev;
+ struct pingpong_context *ctx;
+ struct pingpong_dest my_dest;
+ struct pingpong_dest *rem_dest;
+ struct timeval start, end;
+ char *ib_devname = NULL;
+ char *servername = NULL;
+ int port = 18515;
+ int ib_port = 1;
+ int size = 4096;
+ enum ibv_mtu mtu = IBV_MTU_1024;
+ int rx_depth = 500;
+ int iters = 1000;
+ int use_event = 0;
+ int routs;
+ int rcnt, scnt;
+ int num_cq_events = 0;
+ int sl = 0;
+ int gidx = -1;
+ char gid[33];
+ key_t key = 18515;
+
+ srand48(getpid() * time(NULL));
+
+ while (1) {
+ int c;
+
+ static struct option long_options[] = {
+ { .name = "port", .has_arg = 1, .val = 'p' },
+ { .name = "ib-dev", .has_arg = 1, .val = 'd' },
+ { .name = "ib-port", .has_arg = 1, .val = 'i' },
+ { .name = "size", .has_arg = 1, .val = 's' },
+ { .name = "mtu", .has_arg = 1, .val = 'm' },
+ { .name = "rx-depth", .has_arg = 1, .val = 'r' },
+ { .name = "iters", .has_arg = 1, .val = 'n' },
+ { .name = "sl", .has_arg = 1, .val = 'l' },
+ { .name = "events", .has_arg = 0, .val = 'e' },
+ { .name = "gid-idx", .has_arg = 1, .val = 'g' },
+ { .name = "shm-key", .has_arg = 1, .val = 'S' },
+ { 0 }
+ };
+
+ c = getopt_long(argc, argv, "p:d:i:s:m:r:n:l:eg:S:", long_options, NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'p':
+ port = strtol(optarg, NULL, 0);
+ if (port < 0 || port > 65535) {
+ usage(argv[0]);
+ return 1;
+ }
+ break;
+
+ case 'd':
+ ib_devname = strdupa(optarg);
+ break;
+
+ case 'i':
+ ib_port = strtol(optarg, NULL, 0);
+ if (ib_port < 0) {
+ usage(argv[0]);
+ return 1;
+ }
+ break;
+
+ case 's':
+ size = strtol(optarg, NULL, 0);
+ break;
+
+ case 'm':
+ mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0));
+ if (mtu < 0) {
+ usage(argv[0]);
+ return 1;
+ }
+ break;
+
+ case 'r':
+ rx_depth = strtol(optarg, NULL, 0);
+ break;
+
+ case 'n':
+ iters = strtol(optarg, NULL, 0);
+ break;
+
+ case 'l':
+ sl = strtol(optarg, NULL, 0);
+ break;
+
+ case 'e':
+ ++use_event;
+ break;
+
+ case 'g':
+ gidx = strtol(optarg, NULL, 0);
+ break;
+
+ case 'S':
+ key = strtol(optarg, NULL, 0);
+ break;
+
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ if (optind == argc - 1)
+ servername = strdupa(argv[optind]);
+ else if (optind < argc) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ page_size = sysconf(_SC_PAGESIZE);
+
+ dev_list = ibv_get_device_list(NULL);
+ if (!dev_list) {
+ perror("Failed to get IB devices list");
+ return 1;
+ }
+
+ if (!ib_devname) {
+ ib_dev = *dev_list;
+ if (!ib_dev) {
+ fprintf(stderr, "No IB devices found\n");
+ return 1;
+ }
+ } else {
+ int i;
+ for (i = 0; dev_list[i]; ++i)
+ if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname))
+ break;
+ ib_dev = dev_list[i];
+ if (!ib_dev) {
+ fprintf(stderr, "IB device %s not found\n", ib_devname);
+ return 1;
+ }
+ }
+
+ ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event, key, !servername);
+ if (!ctx)
+ return 1;
+
+ routs = pp_post_recv(ctx, ctx->rx_depth);
+ if (routs < ctx->rx_depth) {
+ fprintf(stderr, "Couldn't post receive (%d)\n", routs);
+ return 1;
+ }
+
+ if (use_event)
+ if (ibv_req_notify_cq(ctx->cq, 0)) {
+ fprintf(stderr, "Couldn't request CQ notification\n");
+ return 1;
+ }
+
+
+ if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) {
+ fprintf(stderr, "Couldn't get port info\n");
+ return 1;
+ }
+
+ my_dest.lid = ctx->portinfo.lid;
+ if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest.lid) {
+ fprintf(stderr, "Couldn't get local LID\n");
+ return 1;
+ }
+
+ if (gidx >= 0) {
+ if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) {
+ fprintf(stderr, "Could not get local gid for gid index %d\n", gidx);
+ return 1;
+ }
+ } else
+ memset(&my_dest.gid, 0, sizeof my_dest.gid);
+
+ my_dest.qpn = ctx->qp->qp_num;
+ my_dest.psn = lrand48() & 0xffffff;
+ inet_ntop(AF_INET6, &my_dest.gid, gid, sizeof gid);
+ printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n",
+ my_dest.lid, my_dest.qpn, my_dest.psn, gid);
+
+
+ if (servername)
+ rem_dest = pp_client_exch_dest(servername, port, &my_dest);
+ else
+ rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest, gidx);
+
+ if (!rem_dest)
+ return 1;
+
+ inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid);
+ printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n",
+ rem_dest->lid, rem_dest->qpn, rem_dest->psn, gid);
+
+ if (servername)
+ if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest, gidx))
+ return 1;
+
+ ctx->pending = PINGPONG_RECV_WRID;
+
+ if (servername) {
+ if (pp_post_send(ctx)) {
+ fprintf(stderr, "Couldn't post send\n");
+ return 1;
+ }
+ ctx->pending |= PINGPONG_SEND_WRID;
+ }
+
+ if (gettimeofday(&start, NULL)) {
+ perror("gettimeofday");
+ return 1;
+ }
+
+ rcnt = scnt = 0;
+ while (rcnt < iters || scnt < iters) {
+ if (use_event) {
+ struct ibv_cq *ev_cq;
+ void *ev_ctx;
+
+ if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) {
+ fprintf(stderr, "Failed to get cq_event\n");
+ return 1;
+ }
+
+ ++num_cq_events;
+
+ if (ev_cq != ctx->cq) {
+ fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq);
+ return 1;
+ }
+
+ if (ibv_req_notify_cq(ctx->cq, 0)) {
+ fprintf(stderr, "Couldn't request CQ notification\n");
+ return 1;
+ }
+ }
+
+ {
+ struct ibv_wc wc[2];
+ int ne, i;
+
+ do {
+ ne = ibv_poll_cq(ctx->cq, 2, wc);
+ if (ne < 0) {
+ fprintf(stderr, "poll CQ failed %d\n", ne);
+ return 1;
+ }
+
+ } while (!use_event && ne < 1);
+
+ for (i = 0; i < ne; ++i) {
+ if (wc[i].status != IBV_WC_SUCCESS) {
+ fprintf(stderr, "Failed status %s (%d) for wr_id %d\n",
+ ibv_wc_status_str(wc[i].status),
+ wc[i].status, (int) wc[i].wr_id);
+ return 1;
+ }
+
+ switch ((int) wc[i].wr_id) {
+ case PINGPONG_SEND_WRID:
+ ++scnt;
+ break;
+
+ case PINGPONG_RECV_WRID:
+ if (--routs <= 1) {
+ routs += pp_post_recv(ctx, ctx->rx_depth - routs);
+ if (routs < ctx->rx_depth) {
+ fprintf(stderr,
+ "Couldn't post receive (%d)\n",
+ routs);
+ return 1;
+ }
+ }
+
+ ++rcnt;
+ break;
+
+ default:
+ fprintf(stderr, "Completion for unknown wr_id %d\n",
+ (int) wc[i].wr_id);
+ return 1;
+ }
+
+ ctx->pending &= ~(int) wc[i].wr_id;
+ if (scnt < iters && !ctx->pending) {
+ if (pp_post_send(ctx)) {
+ fprintf(stderr, "Couldn't post send\n");
+ return 1;
+ }
+ ctx->pending = PINGPONG_RECV_WRID |
+ PINGPONG_SEND_WRID;
+ }
+ }
+ }
+ }
+
+ if (gettimeofday(&end, NULL)) {
+ perror("gettimeofday");
+ return 1;
+ }
+
+ {
+ float usec = (end.tv_sec - start.tv_sec) * 1000000 +
+ (end.tv_usec - start.tv_usec);
+ long long bytes = (long long) size * iters * 2;
+
+ printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n",
+ bytes, usec / 1000000., bytes * 8. / usec);
+ printf("%d iters in %.2f seconds = %.2f usec/iter\n",
+ iters, usec / 1000000., usec / iters);
+ }
+
+ ibv_ack_cq_events(ctx->cq, num_cq_events);
+
+ if (pp_close_ctx(ctx))
+ return 1;
+
+ ibv_free_device_list(dev_list);
+ free(rem_dest);
+
+ return 0;
+}
diff -r 688b7fd31600 include/infiniband/driver.h
--- a/include/infiniband/driver.h Tue Nov 24 11:26:20 2015 -0800
+++ b/include/infiniband/driver.h Tue Nov 24 20:12:48 2015 -0800
@@ -115,6 +115,14 @@
int ibv_cmd_alloc_pd(struct ibv_context *context, struct ibv_pd *pd,
struct ibv_alloc_pd *cmd, size_t cmd_size,
struct ibv_alloc_pd_resp *resp, size_t resp_size);
+int ibv_cmd_alloc_shpd(struct ibv_context *context, struct ibv_pd *pd,
+ uint64_t share_key, struct ibv_shpd *shpd,
+ struct ibv_alloc_shpd *cmd, size_t cmd_size,
+ struct ibv_alloc_shpd_resp *resp, size_t resp_size);
+int ibv_cmd_share_pd(struct ibv_context *context, struct ibv_shpd *shpd,
+ uint64_t share_key, struct ibv_pd *pd,
+ struct ibv_share_pd *cmd, size_t cmd_size,
+ struct ibv_share_pd_resp *resp, size_t resp_size);
int ibv_cmd_dealloc_pd(struct ibv_pd *pd);
int ibv_cmd_open_xrcd(struct ibv_context *context, struct verbs_xrcd *xrcd,
int vxrcd_size,
@@ -128,7 +136,15 @@
struct ibv_mr *mr, struct ibv_reg_mr *cmd,
size_t cmd_size,
struct ibv_reg_mr_resp *resp, size_t resp_size);
+#define IBV_CMD_REG_MR_RELAXED_HAS_RESP_PARAMS
+int ibv_cmd_reg_mr_relaxed(struct ibv_pd *pd, void *addr, size_t length,
+ uint64_t hca_va, int access,
+ struct ibv_mr *mr, struct ibv_reg_mr *cmd,
+ size_t cmd_size,
+ struct ibv_reg_mr_resp *resp, size_t resp_size);
int ibv_cmd_dereg_mr(struct ibv_mr *mr);
+int ibv_cmd_dereg_mr_relaxed(struct ibv_mr *mr);
+int ibv_cmd_flush_relaxed_mr(struct ibv_pd *pd);
int ibv_cmd_create_cq(struct ibv_context *context, int cqe,
struct ibv_comp_channel *channel,
int comp_vector, struct ibv_cq *cq,
diff -r 688b7fd31600 include/infiniband/kern-abi.h
--- a/include/infiniband/kern-abi.h Tue Nov 24 11:26:20 2015 -0800
+++ b/include/infiniband/kern-abi.h Tue Nov 24 20:12:48 2015 -0800
@@ -95,7 +95,27 @@
IB_USER_VERBS_CMD_OPEN_XRCD,
IB_USER_VERBS_CMD_CLOSE_XRCD,
IB_USER_VERBS_CMD_CREATE_XSRQ,
- IB_USER_VERBS_CMD_OPEN_QP
+ IB_USER_VERBS_CMD_OPEN_QP, /* =40 */
+ /*
+ * Note: 0-40 verbs defined above
+ * Start oracle verb additions leaving a gap
+ * for upstream verbs growth.
+ *
+ * We start at 46 which is the starting value used
+ * for these verbs in UEK2 and add them in same
+ * order.
+ *
+ * (Even if we dont care about aligning with UEK2 values,
+ * cannot go beyond 63 because of "struct ib_device"
+ * has uverbs_cmd_mask which is 64 bits wide!)
+ */
+#define IB_USER_VERBS_CMD_ORACLE_ADDS_START 46
+ IB_USER_VERBS_CMD_ALLOC_SHPD = IB_USER_VERBS_CMD_ORACLE_ADDS_START,
+ /* =46 */
+ IB_USER_VERBS_CMD_SHARE_PD, /* =47 */
+ IB_USER_VERBS_CMD_REG_MR_RELAXED, /* =48 */
+ IB_USER_VERBS_CMD_DEREG_MR_RELAXED, /* =49 */
+ IB_USER_VERBS_CMD_FLUSH_RELAXED_MR /* =50 */
};
#define IB_USER_VERBS_CMD_COMMAND_MASK 0xff
@@ -293,6 +313,40 @@
__u32 reserved;
};
+struct ibv_alloc_shpd {
+ __u32 command;
+ __u16 in_words;
+ __u16 out_words;
+ __u64 response;
+ __u32 pd_handle;
+ __u32 reserved;
+ __u64 share_key;
+ __u64 user_handle;
+ __u64 driver_data[0];
+};
+
+struct ibv_alloc_shpd_resp {
+ __u32 shpd_handle;
+ __u32 reserved;
+};
+
+struct ibv_share_pd {
+ __u32 command;
+ __u16 in_words;
+ __u16 out_words;
+ __u64 response;
+ __u32 shpd_handle;
+ __u32 reserved;
+ __u64 share_key;
+ __u64 user_handle;
+ __u64 driver_data[0];
+};
+
+struct ibv_share_pd_resp {
+ __u32 pd_handle;
+ __u32 reserved;
+};
+
struct ibv_dealloc_pd {
__u32 command;
__u16 in_words;
@@ -353,6 +407,15 @@
__u64 user_handle;
};
+struct ibv_flush_relaxed_mr {
+ __u32 command;
+ __u16 in_words;
+ __u16 out_words;
+ __u32 pd_handle;
+ __u32 reserved;
+ __u64 user_handle;
+};
+
struct ibv_create_comp_channel {
__u32 command;
__u16 in_words;
@@ -701,6 +764,7 @@
union {
struct {
__u32 remote_srqn;
+ __u32 reserved;
} xrc;
} qp_type;
};
@@ -1035,7 +1099,12 @@
IB_USER_VERBS_CMD_CREATE_XSRQ_V2 = -1,
IB_USER_VERBS_CMD_OPEN_QP_V2 = -1,
IB_USER_VERBS_CMD_CREATE_FLOW_V2 = -1,
- IB_USER_VERBS_CMD_DESTROY_FLOW_V2 = -1
+ IB_USER_VERBS_CMD_DESTROY_FLOW_V2 = -1,
+ IB_USER_VERBS_CMD_ALLOC_SHPD_V2 = -1,
+ IB_USER_VERBS_CMD_SHARE_PD_V2 = -1,
+ IB_USER_VERBS_CMD_REG_MR_RELAXED_V2 = -1,
+ IB_USER_VERBS_CMD_DEREG_MR_RELAXED_V2 = -1,
+ IB_USER_VERBS_CMD_FLUSH_RELAXED_MR_V2 = -1
};
struct ibv_modify_srq_v3 {
diff -r 688b7fd31600 include/infiniband/verbs.h
--- a/include/infiniband/verbs.h Tue Nov 24 11:26:20 2015 -0800
+++ b/include/infiniband/verbs.h Tue Nov 24 20:12:48 2015 -0800
@@ -342,6 +342,10 @@
struct ibv_context *context;
};
+struct ibv_shpd {
+ uint32_t handle;
+};
+
enum ibv_rereg_mr_flags {
IBV_REREG_MR_CHANGE_TRANSLATION = (1 << 0),
IBV_REREG_MR_CHANGE_PD = (1 << 1),
@@ -941,6 +945,13 @@
int (*detach_mcast)(struct ibv_qp *qp, const union ibv_gid *gid,
uint16_t lid);
void (*async_event)(struct ibv_async_event *event);
+ struct ibv_shpd * (*alloc_shpd)(struct ibv_pd *pd, uint64_t share_key, struct ibv_shpd *shpd);
+ struct ibv_pd * (*share_pd)(struct ibv_context *context, struct ibv_shpd *shpd, uint64_t share_key);
+ struct ibv_mr * (*reg_mr_relaxed)(struct ibv_pd *pd,
+ void *addr, size_t length,
+ int access);
+ int (*dereg_mr_relaxed)(struct ibv_mr *mr);
+ int (*flush_relaxed_mr)(struct ibv_pd *pd);
};
struct ibv_context {
@@ -1128,6 +1139,16 @@
struct ibv_pd *ibv_alloc_pd(struct ibv_context *context);
/**
+ * ibv_alloc_shpd - Mark a pd as shareable & return shareable pd
+ */
+struct ibv_shpd *ibv_alloc_shpd(struct ibv_pd *pd, uint64_t share_key, struct ibv_shpd *shpd);
+
+/**
+ * ibv_share_pd - allocate a process private pd from shared pd
+ */
+struct ibv_pd *ibv_share_pd(struct ibv_context *context, struct ibv_shpd *shpd, uint64_t share_key);
+
+/**
* ibv_dealloc_pd - Free a protection domain
*/
int ibv_dealloc_pd(struct ibv_pd *pd);
@@ -1182,11 +1203,27 @@
size_t length, int access);
/**
+ * ibv_reg_mr_relaxed - Register a memory region using FMR
+ */
+struct ibv_mr *ibv_reg_mr_relaxed(struct ibv_pd *pd, void *addr,
+ size_t length, int access);
+
+/**
* ibv_dereg_mr - Deregister a memory region
*/
int ibv_dereg_mr(struct ibv_mr *mr);
/**
+ * ibv_dereg_mr_relaxed - Deregister a memory region registered using FMR
+ */
+int ibv_dereg_mr_relaxed(struct ibv_mr *mr);
+
+/**
+ * ibv_flush_relaxed_mr - Flush all free mr's in the protection domain
+ */
+int ibv_flush_relaxed_mr(struct ibv_pd *pd);
+
+/**
* ibv_create_comp_channel - Create a completion event channel
*/
struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context);
diff -r 688b7fd31600 man/ibv_shpd_pingpong.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ibv_shpd_pingpong.1 Tue Nov 24 20:12:48 2015 -0800
@@ -0,0 +1,69 @@
+.TH IBV_SHPD_PINGPONG 1 "June 11, 2012" "libibverbs" "USER COMMANDS"
+
+.SH NAME
+ibv_shpd_pingpong \- simple InfiniBand RC transport test that uses shared PD
+
+.SH SYNOPSIS
+.B ibv_shpd_pingpong
+[\-p port] [\-d device] [\-i ib port] [\-s size] [\-r rx depth]
+[\-n iters] [\-l sl] [\-e] [\-S shm key] \fBHOSTNAME\fR
+
+.B ibv_shpd_pingpong
+[\-p port] [\-d device] [\-i ib port] [\-s size] [\-r rx depth]
+[\-n iters] [\-l sl] [\-e] [\-S shm key]
+
+.SH DESCRIPTION
+.PP
+Run a simple ping-pong test over InfiniBand via the reliable
+connected (RC) transport sharing the same PD.
+.PP
+Both server and client must be running on the same machine.
+.SH OPTIONS
+
+.PP
+.TP
+\fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR
+use TCP port \fIPORT\fR for initial synchronization (default 18515)
+.TP
+\fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR
+use IB device \fIDEVICE\fR (default first device found)
+.TP
+\fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR
+use IB port \fIPORT\fR (default port 1)
+.TP
+\fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR
+ping-pong messages of size \fISIZE\fR (default 4096)
+.TP
+\fB\-r\fR, \fB\-\-rx\-depth\fR=\fIDEPTH\fR
+post \fIDEPTH\fR receives at a time (default 1000)
+.TP
+\fB\-n\fR, \fB\-\-iters\fR=\fIITERS\fR
+perform \fIITERS\fR message exchanges (default 1000)
+.TP
+\fB\-l\fR, \fB\-\-sl\fR=\fISL\fR
+use \fISL\fR as the service level value of the QP (default 0)
+.TP
+\fB\-e\fR, \fB\-\-events\fR
+sleep while waiting for work completion events (default is to poll for
+completions)
+.TP
+\fB\-S\fR, \fB\-\-shm\-key\fR=\fIKEY\fR
+value of the shared memory key that both sides will use (default 18515)
+
+.SH SEE ALSO
+.BR ibv_rc_pingpong (1),
+.BR ibv_uc_pingpong (1),
+.BR ibv_ud_pingpong (1),
+.BR ibv_srq_pingpong (1)
+
+.SH AUTHORS
+.TP
+Dotan Barak
+.RI < dotanb@dev.mellanox.co.il >
+
+.SH BUGS
+The network synchronization between client and server instances is
+weak, and does not prevent incompatible options from being used on the
+two instances. The method used for retrieving work completions is not
+strictly correct, and race conditions may cause failures on some
+systems.
diff -r 688b7fd31600 src/cmd.c
--- a/src/cmd.c Tue Nov 24 11:26:20 2015 -0800
+++ b/src/cmd.c Tue Nov 24 20:12:48 2015 -0800
@@ -241,6 +241,51 @@
return 0;
}
+int ibv_cmd_alloc_shpd(struct ibv_context *context, struct ibv_pd *pd,
+ uint64_t share_key, struct ibv_shpd *shpd,
+ struct ibv_alloc_shpd *cmd, size_t cmd_size,
+ struct ibv_alloc_shpd_resp *resp, size_t resp_size)
+{
+ IBV_INIT_CMD_RESP(cmd, cmd_size, ALLOC_SHPD, resp, resp_size);
+ cmd->pd_handle = pd->handle;
+#if defined(__SVR4) && defined(__sun)
+ cmd->user_handle = (uintptr_t) pd;
+#endif
+ cmd->share_key = share_key;
+
+ if (write(context->cmd_fd, cmd, cmd_size) != cmd_size)
+ return errno;
+
+ VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
+
+ shpd->handle = resp->shpd_handle;
+
+ return 0;
+}
+
+int ibv_cmd_share_pd(struct ibv_context *context, struct ibv_shpd *shpd,
+ uint64_t share_key, struct ibv_pd *pd,
+ struct ibv_share_pd *cmd, size_t cmd_size,
+ struct ibv_share_pd_resp *resp, size_t resp_size)
+{
+ IBV_INIT_CMD_RESP(cmd, cmd_size, SHARE_PD, resp, resp_size);
+ cmd->shpd_handle = shpd->handle;
+ cmd->share_key = share_key;
+#if defined(__SVR4) && defined(__sun)
+ cmd->user_handle = (uintptr_t) pd;
+#endif
+
+ if (write(context->cmd_fd, cmd, cmd_size) != cmd_size)
+ return errno;
+
+ VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
+
+ pd->handle = resp->pd_handle;
+ pd->context = context;
+
+ return 0;
+}
+
int ibv_cmd_dealloc_pd(struct ibv_pd *pd)
{
struct ibv_dealloc_pd cmd;
@@ -329,6 +374,37 @@
return 0;
}
+int ibv_cmd_reg_mr_relaxed(struct ibv_pd *pd, void *addr, size_t length,
+ uint64_t hca_va, int access,
+ struct ibv_mr *mr, struct ibv_reg_mr *cmd,
+ size_t cmd_size,
+ struct ibv_reg_mr_resp *resp, size_t resp_size)
+{
+
+ IBV_INIT_CMD_RESP(cmd, cmd_size, REG_MR_RELAXED, resp, resp_size);
+
+ cmd->start = (uintptr_t) addr;
+ cmd->length = length;
+ cmd->hca_va = hca_va;
+ cmd->pd_handle = pd->handle;
+#if defined(__SVR4) && defined(__sun)
+ cmd->user_handle = (uintptr_t) mr;
+#endif
+ cmd->access_flags = access;
+
+ if (write(pd->context->cmd_fd, cmd, cmd_size) != cmd_size)
+ return errno;
+
+ VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
+
+ mr->handle = resp->mr_handle;
+ mr->lkey = resp->lkey;
+ mr->rkey = resp->rkey;
+ mr->context = pd->context;
+
+ return 0;
+}
+
int ibv_cmd_dereg_mr(struct ibv_mr *mr)
{
struct ibv_dereg_mr cmd;
@@ -343,6 +419,38 @@
return 0;
}
+int ibv_cmd_dereg_mr_relaxed(struct ibv_mr *mr)
+{
+ struct ibv_dereg_mr cmd;
+
+ IBV_INIT_CMD(&cmd, sizeof cmd, DEREG_MR_RELAXED);
+ cmd.mr_handle = mr->handle;
+#if defined(__SVR4) && defined(__sun)
+ cmd.user_handle = (uintptr_t) mr;
+#endif
+
+ if (write(mr->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd)
+ return errno;
+
+ return 0;
+}
+
+int ibv_cmd_flush_relaxed_mr(struct ibv_pd *pd)
+{
+ struct ibv_flush_relaxed_mr cmd;
+
+ IBV_INIT_CMD(&cmd, sizeof cmd, FLUSH_RELAXED_MR);
+ cmd.pd_handle = pd->handle;
+#if defined(__SVR4) && defined(__sun)
+ cmd.user_handle = (uintptr_t) pd;
+#endif
+
+ if (write(pd->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd)
+ return errno;
+
+ return 0;
+}
+
int ibv_cmd_create_cq(struct ibv_context *context, int cqe,
struct ibv_comp_channel *channel,
int comp_vector, struct ibv_cq *cq,
@@ -1277,9 +1385,13 @@
return ret;
}
-int ibv_cmd_create_ah_ex(struct ibv_pd *pd, struct ibv_ah *ah, struct ibv_ah_attr *attr,
- struct ibv_create_ah *cmd, size_t cmd_size,
- struct ibv_create_ah_resp *resp, size_t resp_size)
+int ibv_cmd_create_ah_ex(struct ibv_pd *pd,
+ struct ibv_ah *ah,
+ struct ibv_ah_attr *attr,
+ struct ibv_create_ah *cmd,
+ size_t cmd_size,
+ struct ibv_create_ah_resp *resp,
+ size_t resp_size)
{
IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_AH, resp, resp_size);
cmd->user_handle = (uintptr_t) ah;
@@ -1315,7 +1427,9 @@
{
struct ibv_create_ah cmd;
struct ibv_create_ah_resp resp;
- return ibv_cmd_create_ah_ex(pd, ah, attr, &cmd, sizeof(cmd), &resp, sizeof(resp));
+
+ return ibv_cmd_create_ah_ex(pd, ah, attr, &cmd, sizeof(cmd), &resp,
+ sizeof(resp));
}
int ibv_cmd_destroy_ah(struct ibv_ah *ah)
diff -r 688b7fd31600 src/libibverbs.map
--- a/src/libibverbs.map Tue Nov 24 11:26:20 2015 -0800
+++ b/src/libibverbs.map Tue Nov 24 20:12:48 2015 -0800
@@ -13,9 +13,14 @@
ibv_query_gid;
ibv_query_pkey;
ibv_alloc_pd;
+ ibv_alloc_shpd;
+ ibv_share_pd;
ibv_dealloc_pd;
ibv_reg_mr;
+ ibv_reg_mr_relaxed;
ibv_dereg_mr;
+ ibv_dereg_mr_relaxed;
+ ibv_flush_relaxed_mr;
ibv_create_comp_channel;
ibv_destroy_comp_channel;
ibv_create_cq;
@@ -41,9 +46,14 @@
ibv_cmd_query_gid;
ibv_cmd_query_pkey;
ibv_cmd_alloc_pd;
+ ibv_cmd_alloc_shpd;
+ ibv_cmd_share_pd;
ibv_cmd_dealloc_pd;
ibv_cmd_reg_mr;
+ ibv_cmd_reg_mr_relaxed;
ibv_cmd_dereg_mr;
+ ibv_cmd_dereg_mr_relaxed;
+ ibv_cmd_flush_relaxed_mr;
ibv_cmd_create_cq;
ibv_cmd_poll_cq;
ibv_cmd_req_notify_cq;
@@ -61,6 +71,7 @@
ibv_cmd_post_recv;
ibv_cmd_post_srq_recv;
ibv_cmd_create_ah;
+ ibv_cmd_create_ah_ex;
ibv_cmd_destroy_ah;
ibv_cmd_attach_mcast;
ibv_cmd_detach_mcast;
diff -r 688b7fd31600 src/verbs.c
--- a/src/verbs.c Tue Nov 24 11:26:20 2015 -0800
+++ b/src/verbs.c Tue Nov 24 20:12:48 2015 -0800
@@ -215,6 +215,27 @@
}
default_symver(__ibv_alloc_pd, ibv_alloc_pd);
+struct ibv_shpd *__ibv_alloc_shpd(struct ibv_pd *pd, uint64_t share_key, struct ibv_shpd *shpd)
+{
+
+ shpd = pd->context->ops.alloc_shpd(pd, share_key, shpd);
+
+ return shpd;
+}
+default_symver(__ibv_alloc_shpd, ibv_alloc_shpd);
+
+struct ibv_pd *__ibv_share_pd(struct ibv_context *context, struct ibv_shpd *shpd, uint64_t share_key)
+{
+ struct ibv_pd *pd;
+
+ pd = context->ops.share_pd(context, shpd, share_key);
+ if (pd)
+ pd->context = context;
+
+ return pd;
+}
+default_symver(__ibv_share_pd, ibv_share_pd);
+
int __ibv_dealloc_pd(struct ibv_pd *pd)
{
return pd->context->ops.dealloc_pd(pd);
@@ -242,6 +263,27 @@
}
default_symver(__ibv_reg_mr, ibv_reg_mr);
+struct ibv_mr *__ibv_reg_mr_relaxed(struct ibv_pd *pd, void *addr,
+ size_t length, int access)
+{
+ struct ibv_mr *mr;
+
+ if (ibv_dontfork_range(addr, length))
+ return NULL;
+
+ mr = pd->context->ops.reg_mr_relaxed(pd, addr, length, access);
+ if (mr) {
+ mr->context = pd->context;
+ mr->pd = pd;
+ mr->addr = addr;
+ mr->length = length;
+ } else
+ ibv_dofork_range(addr, length);
+
+ return mr;
+}
+default_symver(__ibv_reg_mr_relaxed, ibv_reg_mr_relaxed);
+
int __ibv_dereg_mr(struct ibv_mr *mr)
{
int ret;
@@ -256,6 +298,26 @@
}
default_symver(__ibv_dereg_mr, ibv_dereg_mr);
+int __ibv_dereg_mr_relaxed(struct ibv_mr *mr)
+{
+ int ret;
+ void *addr = mr->addr;
+ size_t length = mr->length;
+
+ ret = mr->context->ops.dereg_mr_relaxed(mr);
+ if (!ret)
+ ibv_dofork_range(addr, length);
+
+ return ret;
+}
+default_symver(__ibv_dereg_mr_relaxed, ibv_dereg_mr_relaxed);
+
+int __ibv_flush_relaxed_mr(struct ibv_pd *pd)
+{
+ return pd->context->ops.flush_relaxed_mr(pd);
+}
+default_symver(__ibv_flush_relaxed_mr, ibv_flush_relaxed_mr);
+
static struct ibv_comp_channel *ibv_create_comp_channel_v2(struct ibv_context *context)
{
struct ibv_abi_compat_v2 *t = context->abi_compat;