1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
3d6b92ffaSHans Petter Selasky  * Copyright (c) 2011 Intel Corporation, Inc.  All rights reserved.
4d6b92ffaSHans Petter Selasky  *
5d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
6d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
7d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
8d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
9d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
10d6b92ffaSHans Petter Selasky  *
11d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
12d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
13d6b92ffaSHans Petter Selasky  *     conditions are met:
14d6b92ffaSHans Petter Selasky  *
15d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
16d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
17d6b92ffaSHans Petter Selasky  *        disclaimer.
18d6b92ffaSHans Petter Selasky  *
19d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
20d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
21d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
22d6b92ffaSHans Petter Selasky  *        provided with the distribution.
23d6b92ffaSHans Petter Selasky  *
24d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31d6b92ffaSHans Petter Selasky  * SOFTWARE.
32d6b92ffaSHans Petter Selasky  */
33d6b92ffaSHans Petter Selasky #define _GNU_SOURCE
34d6b92ffaSHans Petter Selasky #include <config.h>
35d6b92ffaSHans Petter Selasky 
36d6b92ffaSHans Petter Selasky #include <stdio.h>
37d6b92ffaSHans Petter Selasky #include <fcntl.h>
38d6b92ffaSHans Petter Selasky #include <errno.h>
39d6b92ffaSHans Petter Selasky #include <stdlib.h>
40d6b92ffaSHans Petter Selasky #include <unistd.h>
41d6b92ffaSHans Petter Selasky #include <string.h>
42d6b92ffaSHans Petter Selasky #include <sys/types.h>
43d6b92ffaSHans Petter Selasky #include <sys/socket.h>
44d6b92ffaSHans Petter Selasky #include <sys/time.h>
45d6b92ffaSHans Petter Selasky #include <netdb.h>
46d6b92ffaSHans Petter Selasky #include <malloc.h>
47d6b92ffaSHans Petter Selasky #include <getopt.h>
48d6b92ffaSHans Petter Selasky #include <arpa/inet.h>
49d6b92ffaSHans Petter Selasky #include <time.h>
50d6b92ffaSHans Petter Selasky 
51d6b92ffaSHans Petter Selasky #include "pingpong.h"
52d6b92ffaSHans Petter Selasky 
53d6b92ffaSHans Petter Selasky #define MSG_FORMAT "%04x:%06x:%06x:%06x:%06x:%32s"
54d6b92ffaSHans Petter Selasky #define MSG_SIZE   66
55d6b92ffaSHans Petter Selasky #define MSG_SSCAN  "%x:%x:%x:%x:%x:%s"
56d6b92ffaSHans Petter Selasky #define ADDR_FORMAT \
57d6b92ffaSHans Petter Selasky 	"%8s: LID %04x, QPN RECV %06x SEND %06x, PSN %06x, SRQN %06x, GID %s\n"
58d6b92ffaSHans Petter Selasky #define TERMINATION_FORMAT "%s"
59d6b92ffaSHans Petter Selasky #define TERMINATION_MSG_SIZE 4
60d6b92ffaSHans Petter Selasky #define TERMINATION_MSG "END"
61d6b92ffaSHans Petter Selasky static int page_size;
62d6b92ffaSHans Petter Selasky 
63d6b92ffaSHans Petter Selasky struct pingpong_dest {
64d6b92ffaSHans Petter Selasky 	union ibv_gid gid;
65d6b92ffaSHans Petter Selasky 	int lid;
66d6b92ffaSHans Petter Selasky 	int recv_qpn;
67d6b92ffaSHans Petter Selasky 	int send_qpn;
68d6b92ffaSHans Petter Selasky 	int recv_psn;
69d6b92ffaSHans Petter Selasky 	int send_psn;
70d6b92ffaSHans Petter Selasky 	int srqn;
71d6b92ffaSHans Petter Selasky 	int pp_cnt;
72d6b92ffaSHans Petter Selasky 	int sockfd;
73d6b92ffaSHans Petter Selasky };
74d6b92ffaSHans Petter Selasky 
75d6b92ffaSHans Petter Selasky struct pingpong_context {
76d6b92ffaSHans Petter Selasky 	struct ibv_context	*context;
77d6b92ffaSHans Petter Selasky 	struct ibv_comp_channel *channel;
78d6b92ffaSHans Petter Selasky 	struct ibv_pd		*pd;
79d6b92ffaSHans Petter Selasky 	struct ibv_mr		*mr;
80d6b92ffaSHans Petter Selasky 	struct ibv_cq		*send_cq;
81d6b92ffaSHans Petter Selasky 	struct ibv_cq		*recv_cq;
82d6b92ffaSHans Petter Selasky 	struct ibv_srq		*srq;
83d6b92ffaSHans Petter Selasky 	struct ibv_xrcd		*xrcd;
84d6b92ffaSHans Petter Selasky 	struct ibv_qp		**recv_qp;
85d6b92ffaSHans Petter Selasky 	struct ibv_qp		**send_qp;
86d6b92ffaSHans Petter Selasky 	struct pingpong_dest	*rem_dest;
87d6b92ffaSHans Petter Selasky 	void			*buf;
88d6b92ffaSHans Petter Selasky 	int			 lid;
89d6b92ffaSHans Petter Selasky 	int			 sl;
90d6b92ffaSHans Petter Selasky 	enum ibv_mtu		 mtu;
91d6b92ffaSHans Petter Selasky 	int			 ib_port;
92d6b92ffaSHans Petter Selasky 	int			 fd;
93d6b92ffaSHans Petter Selasky 	int			 size;
94d6b92ffaSHans Petter Selasky 	int			 num_clients;
95d6b92ffaSHans Petter Selasky 	int			 num_tests;
96d6b92ffaSHans Petter Selasky 	int			 use_event;
97d6b92ffaSHans Petter Selasky 	int			 gidx;
98d6b92ffaSHans Petter Selasky };
99d6b92ffaSHans Petter Selasky 
100d6b92ffaSHans Petter Selasky static struct pingpong_context ctx;
101d6b92ffaSHans Petter Selasky 
102d6b92ffaSHans Petter Selasky 
open_device(char * ib_devname)103d6b92ffaSHans Petter Selasky static int open_device(char *ib_devname)
104d6b92ffaSHans Petter Selasky {
105d6b92ffaSHans Petter Selasky 	struct ibv_device **dev_list;
106d6b92ffaSHans Petter Selasky 	int i = 0;
107d6b92ffaSHans Petter Selasky 
108d6b92ffaSHans Petter Selasky 	dev_list = ibv_get_device_list(NULL);
109d6b92ffaSHans Petter Selasky 	if (!dev_list) {
110d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Failed to get IB devices list");
111d6b92ffaSHans Petter Selasky 		return -1;
112d6b92ffaSHans Petter Selasky 	}
113d6b92ffaSHans Petter Selasky 
114d6b92ffaSHans Petter Selasky 	if (ib_devname) {
115d6b92ffaSHans Petter Selasky 		for (; dev_list[i]; ++i) {
116d6b92ffaSHans Petter Selasky 			if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname))
117d6b92ffaSHans Petter Selasky 				break;
118d6b92ffaSHans Petter Selasky 		}
119d6b92ffaSHans Petter Selasky 	}
120d6b92ffaSHans Petter Selasky 	if (!dev_list[i]) {
121d6b92ffaSHans Petter Selasky 		fprintf(stderr, "IB device %s not found\n",
122d6b92ffaSHans Petter Selasky 			ib_devname ? ib_devname : "");
123d6b92ffaSHans Petter Selasky 		return -1;
124d6b92ffaSHans Petter Selasky 	}
125d6b92ffaSHans Petter Selasky 
126d6b92ffaSHans Petter Selasky 	ctx.context = ibv_open_device(dev_list[i]);
127d6b92ffaSHans Petter Selasky 	if (!ctx.context) {
128d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't get context for %s\n",
129d6b92ffaSHans Petter Selasky 			ibv_get_device_name(dev_list[i]));
130d6b92ffaSHans Petter Selasky 		return -1;
131d6b92ffaSHans Petter Selasky 	}
132d6b92ffaSHans Petter Selasky 
133d6b92ffaSHans Petter Selasky 	ibv_free_device_list(dev_list);
134d6b92ffaSHans Petter Selasky 	return 0;
135d6b92ffaSHans Petter Selasky }
136d6b92ffaSHans Petter Selasky 
create_qps(void)137d6b92ffaSHans Petter Selasky static int create_qps(void)
138d6b92ffaSHans Petter Selasky {
139d6b92ffaSHans Petter Selasky 	struct ibv_qp_init_attr_ex init;
140d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr mod;
141d6b92ffaSHans Petter Selasky 	int i;
142d6b92ffaSHans Petter Selasky 
143d6b92ffaSHans Petter Selasky 	for (i = 0; i < ctx.num_clients; ++i) {
144d6b92ffaSHans Petter Selasky 
145d6b92ffaSHans Petter Selasky 		memset(&init, 0, sizeof init);
146d6b92ffaSHans Petter Selasky 		init.qp_type = IBV_QPT_XRC_RECV;
147d6b92ffaSHans Petter Selasky 		init.comp_mask = IBV_QP_INIT_ATTR_XRCD;
148d6b92ffaSHans Petter Selasky 		init.xrcd = ctx.xrcd;
149d6b92ffaSHans Petter Selasky 
150d6b92ffaSHans Petter Selasky 		ctx.recv_qp[i] = ibv_create_qp_ex(ctx.context, &init);
151d6b92ffaSHans Petter Selasky 		if (!ctx.recv_qp[i])  {
152d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Couldn't create recv QP[%d] errno %d\n",
153d6b92ffaSHans Petter Selasky 				i, errno);
154d6b92ffaSHans Petter Selasky 			return 1;
155d6b92ffaSHans Petter Selasky 		}
156d6b92ffaSHans Petter Selasky 
157d6b92ffaSHans Petter Selasky 		mod.qp_state        = IBV_QPS_INIT;
158d6b92ffaSHans Petter Selasky 		mod.pkey_index      = 0;
159d6b92ffaSHans Petter Selasky 		mod.port_num        = ctx.ib_port;
160d6b92ffaSHans Petter Selasky 		mod.qp_access_flags = IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_REMOTE_READ;
161d6b92ffaSHans Petter Selasky 
162d6b92ffaSHans Petter Selasky 		if (ibv_modify_qp(ctx.recv_qp[i], &mod,
163d6b92ffaSHans Petter Selasky 				  IBV_QP_STATE | IBV_QP_PKEY_INDEX |
164d6b92ffaSHans Petter Selasky 				  IBV_QP_PORT | IBV_QP_ACCESS_FLAGS)) {
165d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Failed to modify recv QP[%d] to INIT\n", i);
166d6b92ffaSHans Petter Selasky 			return 1;
167d6b92ffaSHans Petter Selasky 		}
168d6b92ffaSHans Petter Selasky 
169d6b92ffaSHans Petter Selasky 		memset(&init, 0, sizeof init);
170d6b92ffaSHans Petter Selasky 		init.qp_type	      = IBV_QPT_XRC_SEND;
171d6b92ffaSHans Petter Selasky 		init.send_cq	      = ctx.send_cq;
172d6b92ffaSHans Petter Selasky 		init.cap.max_send_wr  = ctx.num_clients * ctx.num_tests;
173d6b92ffaSHans Petter Selasky 		init.cap.max_send_sge = 1;
174d6b92ffaSHans Petter Selasky 		init.comp_mask	      = IBV_QP_INIT_ATTR_PD;
175d6b92ffaSHans Petter Selasky 		init.pd		      = ctx.pd;
176d6b92ffaSHans Petter Selasky 
177d6b92ffaSHans Petter Selasky 		ctx.send_qp[i] = ibv_create_qp_ex(ctx.context, &init);
178d6b92ffaSHans Petter Selasky 		if (!ctx.send_qp[i])  {
179d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Couldn't create send QP[%d] errno %d\n",
180d6b92ffaSHans Petter Selasky 				i, errno);
181d6b92ffaSHans Petter Selasky 			return 1;
182d6b92ffaSHans Petter Selasky 		}
183d6b92ffaSHans Petter Selasky 
184d6b92ffaSHans Petter Selasky 		mod.qp_state        = IBV_QPS_INIT;
185d6b92ffaSHans Petter Selasky 		mod.pkey_index      = 0;
186d6b92ffaSHans Petter Selasky 		mod.port_num        = ctx.ib_port;
187d6b92ffaSHans Petter Selasky 		mod.qp_access_flags = 0;
188d6b92ffaSHans Petter Selasky 
189d6b92ffaSHans Petter Selasky 		if (ibv_modify_qp(ctx.send_qp[i], &mod,
190d6b92ffaSHans Petter Selasky 				  IBV_QP_STATE | IBV_QP_PKEY_INDEX |
191d6b92ffaSHans Petter Selasky 				  IBV_QP_PORT | IBV_QP_ACCESS_FLAGS)) {
192d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Failed to modify send QP[%d] to INIT\n", i);
193d6b92ffaSHans Petter Selasky 			return 1;
194d6b92ffaSHans Petter Selasky 		}
195d6b92ffaSHans Petter Selasky 	}
196d6b92ffaSHans Petter Selasky 
197d6b92ffaSHans Petter Selasky 	return 0;
198d6b92ffaSHans Petter Selasky }
199d6b92ffaSHans Petter Selasky 
pp_init_ctx(char * ib_devname)200d6b92ffaSHans Petter Selasky static int pp_init_ctx(char *ib_devname)
201d6b92ffaSHans Petter Selasky {
202d6b92ffaSHans Petter Selasky 	struct ibv_srq_init_attr_ex attr;
203d6b92ffaSHans Petter Selasky 	struct ibv_xrcd_init_attr xrcd_attr;
204d6b92ffaSHans Petter Selasky 	struct ibv_port_attr port_attr;
205d6b92ffaSHans Petter Selasky 
206d6b92ffaSHans Petter Selasky 	ctx.recv_qp = calloc(ctx.num_clients, sizeof *ctx.recv_qp);
207d6b92ffaSHans Petter Selasky 	ctx.send_qp = calloc(ctx.num_clients, sizeof *ctx.send_qp);
208d6b92ffaSHans Petter Selasky 	ctx.rem_dest = calloc(ctx.num_clients, sizeof *ctx.rem_dest);
209d6b92ffaSHans Petter Selasky 	if (!ctx.recv_qp || !ctx.send_qp || !ctx.rem_dest)
210d6b92ffaSHans Petter Selasky 		return 1;
211d6b92ffaSHans Petter Selasky 
212d6b92ffaSHans Petter Selasky 	if (open_device(ib_devname)) {
213d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Failed to open device\n");
214d6b92ffaSHans Petter Selasky 		return 1;
215d6b92ffaSHans Petter Selasky 	}
216d6b92ffaSHans Petter Selasky 
217d6b92ffaSHans Petter Selasky 	if (pp_get_port_info(ctx.context, ctx.ib_port, &port_attr)) {
218d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Failed to get port info\n");
219d6b92ffaSHans Petter Selasky 		return 1;
220d6b92ffaSHans Petter Selasky 	}
221d6b92ffaSHans Petter Selasky 
222d6b92ffaSHans Petter Selasky 	ctx.lid = port_attr.lid;
223d6b92ffaSHans Petter Selasky 	if (port_attr.link_layer != IBV_LINK_LAYER_ETHERNET && !ctx.lid) {
224d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't get local LID\n");
225d6b92ffaSHans Petter Selasky 		return 1;
226d6b92ffaSHans Petter Selasky 	}
227d6b92ffaSHans Petter Selasky 
228d6b92ffaSHans Petter Selasky 	ctx.buf = memalign(page_size, ctx.size);
229d6b92ffaSHans Petter Selasky 	if (!ctx.buf) {
230d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't allocate work buf.\n");
231d6b92ffaSHans Petter Selasky 		return 1;
232d6b92ffaSHans Petter Selasky 	}
233d6b92ffaSHans Petter Selasky 
234d6b92ffaSHans Petter Selasky 	memset(ctx.buf, 0, ctx.size);
235d6b92ffaSHans Petter Selasky 
236d6b92ffaSHans Petter Selasky 	if (ctx.use_event) {
237d6b92ffaSHans Petter Selasky 		ctx.channel = ibv_create_comp_channel(ctx.context);
238d6b92ffaSHans Petter Selasky 		if (!ctx.channel) {
239d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Couldn't create completion channel\n");
240d6b92ffaSHans Petter Selasky 			return 1;
241d6b92ffaSHans Petter Selasky 		}
242d6b92ffaSHans Petter Selasky 	}
243d6b92ffaSHans Petter Selasky 
244d6b92ffaSHans Petter Selasky 	ctx.pd = ibv_alloc_pd(ctx.context);
245d6b92ffaSHans Petter Selasky 	if (!ctx.pd) {
246d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't allocate PD\n");
247d6b92ffaSHans Petter Selasky 		return 1;
248d6b92ffaSHans Petter Selasky 	}
249d6b92ffaSHans Petter Selasky 
250d6b92ffaSHans Petter Selasky 	ctx.mr = ibv_reg_mr(ctx.pd, ctx.buf, ctx.size, IBV_ACCESS_LOCAL_WRITE);
251d6b92ffaSHans Petter Selasky 	if (!ctx.mr) {
252d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't register MR\n");
253d6b92ffaSHans Petter Selasky 		return 1;
254d6b92ffaSHans Petter Selasky 	}
255d6b92ffaSHans Petter Selasky 
256d6b92ffaSHans Petter Selasky 	ctx.fd = open("/tmp/xrc_domain", O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP);
257d6b92ffaSHans Petter Selasky 	if (ctx.fd < 0) {
258d6b92ffaSHans Petter Selasky 		fprintf(stderr,
259d6b92ffaSHans Petter Selasky 			"Couldn't create the file for the XRC Domain "
260d6b92ffaSHans Petter Selasky 			"but not stopping %d\n", errno);
261d6b92ffaSHans Petter Selasky 		ctx.fd = -1;
262d6b92ffaSHans Petter Selasky 	}
263d6b92ffaSHans Petter Selasky 
264d6b92ffaSHans Petter Selasky 	memset(&xrcd_attr, 0, sizeof xrcd_attr);
265d6b92ffaSHans Petter Selasky 	xrcd_attr.comp_mask = IBV_XRCD_INIT_ATTR_FD | IBV_XRCD_INIT_ATTR_OFLAGS;
266d6b92ffaSHans Petter Selasky 	xrcd_attr.fd = ctx.fd;
267d6b92ffaSHans Petter Selasky 	xrcd_attr.oflags = O_CREAT;
268d6b92ffaSHans Petter Selasky 	ctx.xrcd = ibv_open_xrcd(ctx.context, &xrcd_attr);
269d6b92ffaSHans Petter Selasky 	if (!ctx.xrcd) {
270d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't Open the XRC Domain %d\n", errno);
271d6b92ffaSHans Petter Selasky 		return 1;
272d6b92ffaSHans Petter Selasky 	}
273d6b92ffaSHans Petter Selasky 
274d6b92ffaSHans Petter Selasky 	ctx.recv_cq = ibv_create_cq(ctx.context, ctx.num_clients, &ctx.recv_cq,
275d6b92ffaSHans Petter Selasky 				    ctx.channel, 0);
276d6b92ffaSHans Petter Selasky 	if (!ctx.recv_cq) {
277d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't create recv CQ\n");
278d6b92ffaSHans Petter Selasky 		return 1;
279d6b92ffaSHans Petter Selasky 	}
280d6b92ffaSHans Petter Selasky 
281d6b92ffaSHans Petter Selasky 	if (ctx.use_event) {
282d6b92ffaSHans Petter Selasky 		if (ibv_req_notify_cq(ctx.recv_cq, 0)) {
283d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Couldn't request CQ notification\n");
284d6b92ffaSHans Petter Selasky 			return 1;
285d6b92ffaSHans Petter Selasky 		}
286d6b92ffaSHans Petter Selasky 	}
287d6b92ffaSHans Petter Selasky 
288d6b92ffaSHans Petter Selasky 	ctx.send_cq = ibv_create_cq(ctx.context, ctx.num_clients, NULL, NULL, 0);
289d6b92ffaSHans Petter Selasky 	if (!ctx.send_cq) {
290d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't create send CQ\n");
291d6b92ffaSHans Petter Selasky 		return 1;
292d6b92ffaSHans Petter Selasky 	}
293d6b92ffaSHans Petter Selasky 
294d6b92ffaSHans Petter Selasky 	memset(&attr, 0, sizeof attr);
295d6b92ffaSHans Petter Selasky 	attr.attr.max_wr = ctx.num_clients;
296d6b92ffaSHans Petter Selasky 	attr.attr.max_sge = 1;
297d6b92ffaSHans Petter Selasky 	attr.comp_mask = IBV_SRQ_INIT_ATTR_TYPE | IBV_SRQ_INIT_ATTR_XRCD |
298d6b92ffaSHans Petter Selasky 			 IBV_SRQ_INIT_ATTR_CQ | IBV_SRQ_INIT_ATTR_PD;
299d6b92ffaSHans Petter Selasky 	attr.srq_type = IBV_SRQT_XRC;
300d6b92ffaSHans Petter Selasky 	attr.xrcd = ctx.xrcd;
301d6b92ffaSHans Petter Selasky 	attr.cq = ctx.recv_cq;
302d6b92ffaSHans Petter Selasky 	attr.pd = ctx.pd;
303d6b92ffaSHans Petter Selasky 
304d6b92ffaSHans Petter Selasky 	ctx.srq = ibv_create_srq_ex(ctx.context, &attr);
305d6b92ffaSHans Petter Selasky 	if (!ctx.srq)  {
306d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't create SRQ\n");
307d6b92ffaSHans Petter Selasky 		return 1;
308d6b92ffaSHans Petter Selasky 	}
309d6b92ffaSHans Petter Selasky 
310d6b92ffaSHans Petter Selasky 	if (create_qps())
311d6b92ffaSHans Petter Selasky 		return 1;
312d6b92ffaSHans Petter Selasky 
313d6b92ffaSHans Petter Selasky 	return 0;
314d6b92ffaSHans Petter Selasky }
315d6b92ffaSHans Petter Selasky 
recv_termination_ack(int index)316d6b92ffaSHans Petter Selasky static int recv_termination_ack(int index)
317d6b92ffaSHans Petter Selasky {
318d6b92ffaSHans Petter Selasky 	char msg[TERMINATION_MSG_SIZE];
319d6b92ffaSHans Petter Selasky 	int n = 0, r;
320d6b92ffaSHans Petter Selasky 	int sockfd = ctx.rem_dest[index].sockfd;
321d6b92ffaSHans Petter Selasky 
322d6b92ffaSHans Petter Selasky 	while (n < TERMINATION_MSG_SIZE) {
323d6b92ffaSHans Petter Selasky 		r = read(sockfd, msg + n, TERMINATION_MSG_SIZE - n);
324d6b92ffaSHans Petter Selasky 		if (r < 0) {
325d6b92ffaSHans Petter Selasky 			perror("client read");
326d6b92ffaSHans Petter Selasky 			fprintf(stderr,
327d6b92ffaSHans Petter Selasky 				"%d/%d: Couldn't read remote termination ack\n",
328d6b92ffaSHans Petter Selasky 				n, TERMINATION_MSG_SIZE);
329d6b92ffaSHans Petter Selasky 			return 1;
330d6b92ffaSHans Petter Selasky 		}
331d6b92ffaSHans Petter Selasky 		n += r;
332d6b92ffaSHans Petter Selasky 	}
333d6b92ffaSHans Petter Selasky 
334d6b92ffaSHans Petter Selasky 	if (strcmp(msg, TERMINATION_MSG)) {
335d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Invalid termination ack was accepted\n");
336d6b92ffaSHans Petter Selasky 		return 1;
337d6b92ffaSHans Petter Selasky 	}
338d6b92ffaSHans Petter Selasky 
339d6b92ffaSHans Petter Selasky 	return 0;
340d6b92ffaSHans Petter Selasky }
341d6b92ffaSHans Petter Selasky 
send_termination_ack(int index)342d6b92ffaSHans Petter Selasky static int send_termination_ack(int index)
343d6b92ffaSHans Petter Selasky {
344d6b92ffaSHans Petter Selasky 	char msg[TERMINATION_MSG_SIZE];
345d6b92ffaSHans Petter Selasky 	int sockfd = ctx.rem_dest[index].sockfd;
346d6b92ffaSHans Petter Selasky 
347d6b92ffaSHans Petter Selasky 	sprintf(msg, TERMINATION_FORMAT, TERMINATION_MSG);
348d6b92ffaSHans Petter Selasky 
349d6b92ffaSHans Petter Selasky 	if (write(sockfd, msg, TERMINATION_MSG_SIZE) != TERMINATION_MSG_SIZE) {
350d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't send termination ack\n");
351d6b92ffaSHans Petter Selasky 		return 1;
352d6b92ffaSHans Petter Selasky 	}
353d6b92ffaSHans Petter Selasky 
354d6b92ffaSHans Petter Selasky 	return 0;
355d6b92ffaSHans Petter Selasky }
356d6b92ffaSHans Petter Selasky 
pp_client_termination(void)357d6b92ffaSHans Petter Selasky static int pp_client_termination(void)
358d6b92ffaSHans Petter Selasky {
359d6b92ffaSHans Petter Selasky 	if (send_termination_ack(0))
360d6b92ffaSHans Petter Selasky 		return 1;
361d6b92ffaSHans Petter Selasky 	if (recv_termination_ack(0))
362d6b92ffaSHans Petter Selasky 		return 1;
363d6b92ffaSHans Petter Selasky 
364d6b92ffaSHans Petter Selasky 	return 0;
365d6b92ffaSHans Petter Selasky }
366d6b92ffaSHans Petter Selasky 
pp_server_termination(void)367d6b92ffaSHans Petter Selasky static int pp_server_termination(void)
368d6b92ffaSHans Petter Selasky {
369d6b92ffaSHans Petter Selasky 	int i;
370d6b92ffaSHans Petter Selasky 
371d6b92ffaSHans Petter Selasky 	for (i = 0; i < ctx.num_clients; i++) {
372d6b92ffaSHans Petter Selasky 		if (recv_termination_ack(i))
373d6b92ffaSHans Petter Selasky 			return 1;
374d6b92ffaSHans Petter Selasky 	}
375d6b92ffaSHans Petter Selasky 
376d6b92ffaSHans Petter Selasky 	for (i = 0; i < ctx.num_clients; i++) {
377d6b92ffaSHans Petter Selasky 		if (send_termination_ack(i))
378d6b92ffaSHans Petter Selasky 			return 1;
379d6b92ffaSHans Petter Selasky 	}
380d6b92ffaSHans Petter Selasky 
381d6b92ffaSHans Petter Selasky 	return 0;
382d6b92ffaSHans Petter Selasky }
383d6b92ffaSHans Petter Selasky 
send_local_dest(int sockfd,int index)384d6b92ffaSHans Petter Selasky static int send_local_dest(int sockfd, int index)
385d6b92ffaSHans Petter Selasky {
386d6b92ffaSHans Petter Selasky 	char msg[MSG_SIZE];
387d6b92ffaSHans Petter Selasky 	char gid[33];
388d6b92ffaSHans Petter Selasky 	uint32_t srq_num;
389d6b92ffaSHans Petter Selasky 	union ibv_gid local_gid;
390d6b92ffaSHans Petter Selasky 
391d6b92ffaSHans Petter Selasky 	if (ctx.gidx >= 0) {
392d6b92ffaSHans Petter Selasky 		if (ibv_query_gid(ctx.context, ctx.ib_port, ctx.gidx,
393d6b92ffaSHans Petter Selasky 				  &local_gid)) {
394d6b92ffaSHans Petter Selasky 			fprintf(stderr, "can't read sgid of index %d\n",
395d6b92ffaSHans Petter Selasky 				ctx.gidx);
396d6b92ffaSHans Petter Selasky 			return -1;
397d6b92ffaSHans Petter Selasky 		}
398d6b92ffaSHans Petter Selasky 	} else {
399d6b92ffaSHans Petter Selasky 		memset(&local_gid, 0, sizeof(local_gid));
400d6b92ffaSHans Petter Selasky 	}
401d6b92ffaSHans Petter Selasky 
402d6b92ffaSHans Petter Selasky 	ctx.rem_dest[index].recv_psn = lrand48() & 0xffffff;
403d6b92ffaSHans Petter Selasky 	if (ibv_get_srq_num(ctx.srq, &srq_num)) {
404d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't get SRQ num\n");
405d6b92ffaSHans Petter Selasky 		return -1;
406d6b92ffaSHans Petter Selasky 	}
407d6b92ffaSHans Petter Selasky 
408d6b92ffaSHans Petter Selasky 	inet_ntop(AF_INET6, &local_gid, gid, sizeof(gid));
409d6b92ffaSHans Petter Selasky 	printf(ADDR_FORMAT, "local", ctx.lid, ctx.recv_qp[index]->qp_num,
410d6b92ffaSHans Petter Selasky 		ctx.send_qp[index]->qp_num, ctx.rem_dest[index].recv_psn,
411d6b92ffaSHans Petter Selasky 		srq_num, gid);
412d6b92ffaSHans Petter Selasky 
413d6b92ffaSHans Petter Selasky 	gid_to_wire_gid(&local_gid, gid);
414d6b92ffaSHans Petter Selasky 	sprintf(msg, MSG_FORMAT, ctx.lid, ctx.recv_qp[index]->qp_num,
415d6b92ffaSHans Petter Selasky 		ctx.send_qp[index]->qp_num, ctx.rem_dest[index].recv_psn,
416d6b92ffaSHans Petter Selasky 		srq_num, gid);
417d6b92ffaSHans Petter Selasky 
418d6b92ffaSHans Petter Selasky 	if (write(sockfd, msg, MSG_SIZE) != MSG_SIZE) {
419d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't send local address\n");
420d6b92ffaSHans Petter Selasky 		return -1;
421d6b92ffaSHans Petter Selasky 	}
422d6b92ffaSHans Petter Selasky 
423d6b92ffaSHans Petter Selasky 	return 0;
424d6b92ffaSHans Petter Selasky }
425d6b92ffaSHans Petter Selasky 
recv_remote_dest(int sockfd,int index)426d6b92ffaSHans Petter Selasky static int recv_remote_dest(int sockfd, int index)
427d6b92ffaSHans Petter Selasky {
428d6b92ffaSHans Petter Selasky 	struct pingpong_dest *rem_dest;
429d6b92ffaSHans Petter Selasky 	char msg[MSG_SIZE];
430d6b92ffaSHans Petter Selasky 	char gid[33];
431d6b92ffaSHans Petter Selasky 	int n = 0, r;
432d6b92ffaSHans Petter Selasky 
433d6b92ffaSHans Petter Selasky 	while (n < MSG_SIZE) {
434d6b92ffaSHans Petter Selasky 		r = read(sockfd, msg + n, MSG_SIZE - n);
435d6b92ffaSHans Petter Selasky 		if (r < 0) {
436d6b92ffaSHans Petter Selasky 			perror("client read");
437d6b92ffaSHans Petter Selasky 			fprintf(stderr,
438d6b92ffaSHans Petter Selasky 				"%d/%d: Couldn't read remote address [%d]\n",
439d6b92ffaSHans Petter Selasky 				n, MSG_SIZE, index);
440d6b92ffaSHans Petter Selasky 			return -1;
441d6b92ffaSHans Petter Selasky 		}
442d6b92ffaSHans Petter Selasky 		n += r;
443d6b92ffaSHans Petter Selasky 	}
444d6b92ffaSHans Petter Selasky 
445d6b92ffaSHans Petter Selasky 	rem_dest = &ctx.rem_dest[index];
446d6b92ffaSHans Petter Selasky 	sscanf(msg, MSG_SSCAN, &rem_dest->lid, &rem_dest->recv_qpn,
447d6b92ffaSHans Petter Selasky 		&rem_dest->send_qpn, &rem_dest->send_psn, &rem_dest->srqn, gid);
448d6b92ffaSHans Petter Selasky 
449d6b92ffaSHans Petter Selasky 	wire_gid_to_gid(gid, &rem_dest->gid);
450d6b92ffaSHans Petter Selasky 	inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof(gid));
451d6b92ffaSHans Petter Selasky 	printf(ADDR_FORMAT, "remote", rem_dest->lid, rem_dest->recv_qpn,
452d6b92ffaSHans Petter Selasky 		rem_dest->send_qpn, rem_dest->send_psn, rem_dest->srqn,
453d6b92ffaSHans Petter Selasky 		gid);
454d6b92ffaSHans Petter Selasky 
455d6b92ffaSHans Petter Selasky 	rem_dest->sockfd = sockfd;
456d6b92ffaSHans Petter Selasky 	return 0;
457d6b92ffaSHans Petter Selasky }
458d6b92ffaSHans Petter Selasky 
set_ah_attr(struct ibv_ah_attr * attr,struct pingpong_context * myctx,int index)459d6b92ffaSHans Petter Selasky static void set_ah_attr(struct ibv_ah_attr *attr, struct pingpong_context *myctx,
460d6b92ffaSHans Petter Selasky 			int index)
461d6b92ffaSHans Petter Selasky {
462d6b92ffaSHans Petter Selasky 	attr->is_global = 1;
463d6b92ffaSHans Petter Selasky 	attr->grh.hop_limit = 5;
464d6b92ffaSHans Petter Selasky 	attr->grh.dgid = myctx->rem_dest[index].gid;
465d6b92ffaSHans Petter Selasky 	attr->grh.sgid_index = myctx->gidx;
466d6b92ffaSHans Petter Selasky }
467d6b92ffaSHans Petter Selasky 
connect_qps(int index)468d6b92ffaSHans Petter Selasky static int connect_qps(int index)
469d6b92ffaSHans Petter Selasky {
470d6b92ffaSHans Petter Selasky 	struct ibv_qp_attr attr;
471d6b92ffaSHans Petter Selasky 
472d6b92ffaSHans Petter Selasky 	memset(&attr, 0, sizeof attr);
473d6b92ffaSHans Petter Selasky 	attr.qp_state	      = IBV_QPS_RTR;
474d6b92ffaSHans Petter Selasky 	attr.dest_qp_num      = ctx.rem_dest[index].send_qpn;
475d6b92ffaSHans Petter Selasky 	attr.path_mtu	      = ctx.mtu;
476d6b92ffaSHans Petter Selasky 	attr.rq_psn	      = ctx.rem_dest[index].send_psn;
477d6b92ffaSHans Petter Selasky 	attr.min_rnr_timer    = 12;
478d6b92ffaSHans Petter Selasky 	attr.ah_attr.dlid     = ctx.rem_dest[index].lid;
479d6b92ffaSHans Petter Selasky 	attr.ah_attr.sl	      = ctx.sl;
480d6b92ffaSHans Petter Selasky 	attr.ah_attr.port_num = ctx.ib_port;
481d6b92ffaSHans Petter Selasky 
482d6b92ffaSHans Petter Selasky 	if (ctx.rem_dest[index].gid.global.interface_id)
483d6b92ffaSHans Petter Selasky 		set_ah_attr(&attr.ah_attr, &ctx, index);
484d6b92ffaSHans Petter Selasky 
485d6b92ffaSHans Petter Selasky 	if (ibv_modify_qp(ctx.recv_qp[index], &attr,
486d6b92ffaSHans Petter Selasky 			  IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU |
487d6b92ffaSHans Petter Selasky 			  IBV_QP_DEST_QPN | IBV_QP_RQ_PSN |
488d6b92ffaSHans Petter Selasky 			  IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER)) {
489d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Failed to modify recv QP[%d] to RTR\n", index);
490d6b92ffaSHans Petter Selasky 		return 1;
491d6b92ffaSHans Petter Selasky 	}
492d6b92ffaSHans Petter Selasky 
493d6b92ffaSHans Petter Selasky 	memset(&attr, 0, sizeof attr);
494d6b92ffaSHans Petter Selasky 	attr.qp_state = IBV_QPS_RTS;
495d6b92ffaSHans Petter Selasky 	attr.timeout = 14;
496d6b92ffaSHans Petter Selasky 	attr.sq_psn = ctx.rem_dest[index].recv_psn;
497d6b92ffaSHans Petter Selasky 
498d6b92ffaSHans Petter Selasky 	if (ibv_modify_qp(ctx.recv_qp[index], &attr,
499d6b92ffaSHans Petter Selasky 			  IBV_QP_STATE | IBV_QP_TIMEOUT | IBV_QP_SQ_PSN)) {
500d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Failed to modify recv QP[%d] to RTS\n", index);
501d6b92ffaSHans Petter Selasky 		return 1;
502d6b92ffaSHans Petter Selasky 	}
503d6b92ffaSHans Petter Selasky 
504d6b92ffaSHans Petter Selasky 	memset(&attr, 0, sizeof attr);
505d6b92ffaSHans Petter Selasky 	attr.qp_state	      = IBV_QPS_RTR;
506d6b92ffaSHans Petter Selasky 	attr.dest_qp_num      = ctx.rem_dest[index].recv_qpn;
507d6b92ffaSHans Petter Selasky 	attr.path_mtu	      = ctx.mtu;
508d6b92ffaSHans Petter Selasky 	attr.rq_psn	      = ctx.rem_dest[index].send_psn;
509d6b92ffaSHans Petter Selasky 	attr.ah_attr.dlid     = ctx.rem_dest[index].lid;
510d6b92ffaSHans Petter Selasky 	attr.ah_attr.sl	      = ctx.sl;
511d6b92ffaSHans Petter Selasky 	attr.ah_attr.port_num = ctx.ib_port;
512d6b92ffaSHans Petter Selasky 
513d6b92ffaSHans Petter Selasky 	if (ctx.rem_dest[index].gid.global.interface_id)
514d6b92ffaSHans Petter Selasky 		set_ah_attr(&attr.ah_attr, &ctx, index);
515d6b92ffaSHans Petter Selasky 
516d6b92ffaSHans Petter Selasky 	if (ibv_modify_qp(ctx.send_qp[index], &attr,
517d6b92ffaSHans Petter Selasky 			  IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU |
518d6b92ffaSHans Petter Selasky 			  IBV_QP_DEST_QPN | IBV_QP_RQ_PSN)) {
519d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Failed to modify send QP[%d] to RTR\n", index);
520d6b92ffaSHans Petter Selasky 		return 1;
521d6b92ffaSHans Petter Selasky 	}
522d6b92ffaSHans Petter Selasky 
523d6b92ffaSHans Petter Selasky 	memset(&attr, 0, sizeof attr);
524d6b92ffaSHans Petter Selasky 	attr.qp_state = IBV_QPS_RTS;
525d6b92ffaSHans Petter Selasky 	attr.timeout = 14;
526d6b92ffaSHans Petter Selasky 	attr.retry_cnt = 7;
527d6b92ffaSHans Petter Selasky 	attr.rnr_retry = 7;
528d6b92ffaSHans Petter Selasky 	attr.sq_psn = ctx.rem_dest[index].recv_psn;
529d6b92ffaSHans Petter Selasky 
530d6b92ffaSHans Petter Selasky 	if (ibv_modify_qp(ctx.send_qp[index], &attr,
531d6b92ffaSHans Petter Selasky 			  IBV_QP_STATE | IBV_QP_TIMEOUT | IBV_QP_SQ_PSN |
532d6b92ffaSHans Petter Selasky 			  IBV_QP_RETRY_CNT | IBV_QP_RNR_RETRY | IBV_QP_MAX_QP_RD_ATOMIC)) {
533d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Failed to modify send QP[%d] to RTS\n", index);
534d6b92ffaSHans Petter Selasky 		return 1;
535d6b92ffaSHans Petter Selasky 	}
536d6b92ffaSHans Petter Selasky 
537d6b92ffaSHans Petter Selasky 	return 0;
538d6b92ffaSHans Petter Selasky }
539d6b92ffaSHans Petter Selasky 
pp_client_connect(const char * servername,int port)540d6b92ffaSHans Petter Selasky static int pp_client_connect(const char *servername, int port)
541d6b92ffaSHans Petter Selasky {
542d6b92ffaSHans Petter Selasky 	struct addrinfo *res, *t;
543d6b92ffaSHans Petter Selasky 	char *service;
544d6b92ffaSHans Petter Selasky 	int ret;
545d6b92ffaSHans Petter Selasky 	int sockfd = -1;
546d6b92ffaSHans Petter Selasky 	struct addrinfo hints = {
5473468ddceSHans Petter Selasky 		.ai_family   = AF_UNSPEC,
548d6b92ffaSHans Petter Selasky 		.ai_socktype = SOCK_STREAM
549d6b92ffaSHans Petter Selasky 	};
550d6b92ffaSHans Petter Selasky 
551d6b92ffaSHans Petter Selasky 	if (asprintf(&service, "%d", port) < 0)
552d6b92ffaSHans Petter Selasky 		return 1;
553d6b92ffaSHans Petter Selasky 
554d6b92ffaSHans Petter Selasky 	ret = getaddrinfo(servername, service, &hints, &res);
555d6b92ffaSHans Petter Selasky 	if (ret < 0) {
556d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s for %s:%d\n", gai_strerror(ret), servername, port);
557d6b92ffaSHans Petter Selasky 		free(service);
558d6b92ffaSHans Petter Selasky 		return 1;
559d6b92ffaSHans Petter Selasky 	}
560d6b92ffaSHans Petter Selasky 
561d6b92ffaSHans Petter Selasky 	for (t = res; t; t = t->ai_next) {
562d6b92ffaSHans Petter Selasky 		sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
563d6b92ffaSHans Petter Selasky 		if (sockfd >= 0) {
564d6b92ffaSHans Petter Selasky 			if (!connect(sockfd, t->ai_addr, t->ai_addrlen))
565d6b92ffaSHans Petter Selasky 				break;
566d6b92ffaSHans Petter Selasky 			close(sockfd);
567d6b92ffaSHans Petter Selasky 			sockfd = -1;
568d6b92ffaSHans Petter Selasky 		}
569d6b92ffaSHans Petter Selasky 	}
570d6b92ffaSHans Petter Selasky 
571d6b92ffaSHans Petter Selasky 	freeaddrinfo_null(res);
572d6b92ffaSHans Petter Selasky 	free(service);
573d6b92ffaSHans Petter Selasky 
574d6b92ffaSHans Petter Selasky 	if (sockfd < 0) {
575d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port);
576d6b92ffaSHans Petter Selasky 		return 1;
577d6b92ffaSHans Petter Selasky 	}
578d6b92ffaSHans Petter Selasky 
579d6b92ffaSHans Petter Selasky 	if (send_local_dest(sockfd, 0))
580d6b92ffaSHans Petter Selasky 		return 1;
581d6b92ffaSHans Petter Selasky 
582d6b92ffaSHans Petter Selasky 	if (recv_remote_dest(sockfd, 0))
583d6b92ffaSHans Petter Selasky 		return 1;
584d6b92ffaSHans Petter Selasky 
585d6b92ffaSHans Petter Selasky 	if (connect_qps(0))
586d6b92ffaSHans Petter Selasky 		return 1;
587d6b92ffaSHans Petter Selasky 
588d6b92ffaSHans Petter Selasky 	return 0;
589d6b92ffaSHans Petter Selasky }
590d6b92ffaSHans Petter Selasky 
pp_server_connect(int port)591d6b92ffaSHans Petter Selasky static int pp_server_connect(int port)
592d6b92ffaSHans Petter Selasky {
593d6b92ffaSHans Petter Selasky 	struct addrinfo *res, *t;
594d6b92ffaSHans Petter Selasky 	char *service;
595d6b92ffaSHans Petter Selasky 	int ret, i, n;
596d6b92ffaSHans Petter Selasky 	int sockfd = -1, connfd;
597d6b92ffaSHans Petter Selasky 	struct addrinfo hints = {
598d6b92ffaSHans Petter Selasky 		.ai_flags    = AI_PASSIVE,
59935c87c07SPiotr Kubaj 		.ai_family   = AF_UNSPEC,
600d6b92ffaSHans Petter Selasky 		.ai_socktype = SOCK_STREAM
601d6b92ffaSHans Petter Selasky 	};
602d6b92ffaSHans Petter Selasky 
603d6b92ffaSHans Petter Selasky 	if (asprintf(&service, "%d", port) < 0)
604d6b92ffaSHans Petter Selasky 		return 1;
605d6b92ffaSHans Petter Selasky 
606d6b92ffaSHans Petter Selasky 	ret = getaddrinfo(NULL, service, &hints, &res);
607d6b92ffaSHans Petter Selasky 	if (ret < 0) {
608d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s for port %d\n", gai_strerror(ret), port);
609d6b92ffaSHans Petter Selasky 		free(service);
610d6b92ffaSHans Petter Selasky 		return 1;
611d6b92ffaSHans Petter Selasky 	}
612d6b92ffaSHans Petter Selasky 
613d6b92ffaSHans Petter Selasky 	for (t = res; t; t = t->ai_next) {
614d6b92ffaSHans Petter Selasky 		sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
615d6b92ffaSHans Petter Selasky 		if (sockfd >= 0) {
616d6b92ffaSHans Petter Selasky 			n = 1;
617d6b92ffaSHans Petter Selasky 			setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n);
618d6b92ffaSHans Petter Selasky 			if (!bind(sockfd, t->ai_addr, t->ai_addrlen))
619d6b92ffaSHans Petter Selasky 				break;
620d6b92ffaSHans Petter Selasky 			close(sockfd);
621d6b92ffaSHans Petter Selasky 			sockfd = -1;
622d6b92ffaSHans Petter Selasky 		}
623d6b92ffaSHans Petter Selasky 	}
624d6b92ffaSHans Petter Selasky 
625d6b92ffaSHans Petter Selasky 	freeaddrinfo_null(res);
626d6b92ffaSHans Petter Selasky 	free(service);
627d6b92ffaSHans Petter Selasky 
628d6b92ffaSHans Petter Selasky 	if (sockfd < 0) {
629d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't listen to port %d\n", port);
630d6b92ffaSHans Petter Selasky 		return 1;
631d6b92ffaSHans Petter Selasky 	}
632d6b92ffaSHans Petter Selasky 
6338ca1ed33SEric van Gyzen 	if (listen(sockfd, ctx.num_clients) < 0) {
634d13def78SEric van Gyzen 		perror("listen() failed");
635d13def78SEric van Gyzen 		close(sockfd);
636d13def78SEric van Gyzen 		return 1;
637d13def78SEric van Gyzen 	}
638d6b92ffaSHans Petter Selasky 
639d6b92ffaSHans Petter Selasky 	for (i = 0; i < ctx.num_clients; i++) {
640d6b92ffaSHans Petter Selasky 		connfd = accept(sockfd, NULL, NULL);
641d6b92ffaSHans Petter Selasky 		if (connfd < 0) {
642d6b92ffaSHans Petter Selasky 			fprintf(stderr, "accept() failed for client %d\n", i);
643d6b92ffaSHans Petter Selasky 			return 1;
644d6b92ffaSHans Petter Selasky 		}
645d6b92ffaSHans Petter Selasky 
646d6b92ffaSHans Petter Selasky 		if (recv_remote_dest(connfd, i))
647d6b92ffaSHans Petter Selasky 			return 1;
648d6b92ffaSHans Petter Selasky 
649d6b92ffaSHans Petter Selasky 		if (send_local_dest(connfd, i))
650d6b92ffaSHans Petter Selasky 			return 1;
651d6b92ffaSHans Petter Selasky 
652d6b92ffaSHans Petter Selasky 		if (connect_qps(i))
653d6b92ffaSHans Petter Selasky 			return 1;
654d6b92ffaSHans Petter Selasky 	}
655d6b92ffaSHans Petter Selasky 
656d6b92ffaSHans Petter Selasky 	close(sockfd);
657d6b92ffaSHans Petter Selasky 	return 0;
658d6b92ffaSHans Petter Selasky }
659d6b92ffaSHans Petter Selasky 
660d6b92ffaSHans Petter Selasky 
pp_close_ctx(void)661d6b92ffaSHans Petter Selasky static int pp_close_ctx(void)
662d6b92ffaSHans Petter Selasky {
663d6b92ffaSHans Petter Selasky 	int i;
664d6b92ffaSHans Petter Selasky 
665d6b92ffaSHans Petter Selasky 	for (i = 0; i < ctx.num_clients; ++i) {
666d6b92ffaSHans Petter Selasky 
667d6b92ffaSHans Petter Selasky 		if (ibv_destroy_qp(ctx.send_qp[i])) {
668d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Couldn't destroy INI QP[%d]\n", i);
669d6b92ffaSHans Petter Selasky 			return 1;
670d6b92ffaSHans Petter Selasky 		}
671d6b92ffaSHans Petter Selasky 
672d6b92ffaSHans Petter Selasky 		if (ibv_destroy_qp(ctx.recv_qp[i])) {
673d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Couldn't destroy TGT QP[%d]\n", i);
674d6b92ffaSHans Petter Selasky 			return 1;
675d6b92ffaSHans Petter Selasky 		}
676d6b92ffaSHans Petter Selasky 
677d6b92ffaSHans Petter Selasky 		if (ctx.rem_dest[i].sockfd)
678d6b92ffaSHans Petter Selasky 			close(ctx.rem_dest[i].sockfd);
679d6b92ffaSHans Petter Selasky 	}
680d6b92ffaSHans Petter Selasky 
681d6b92ffaSHans Petter Selasky 	if (ibv_destroy_srq(ctx.srq)) {
682d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't destroy SRQ\n");
683d6b92ffaSHans Petter Selasky 		return 1;
684d6b92ffaSHans Petter Selasky 	}
685d6b92ffaSHans Petter Selasky 
686d6b92ffaSHans Petter Selasky 	if (ctx.xrcd && ibv_close_xrcd(ctx.xrcd)) {
687d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't close the XRC Domain\n");
688d6b92ffaSHans Petter Selasky 		return 1;
689d6b92ffaSHans Petter Selasky 	}
690d6b92ffaSHans Petter Selasky 	if (ctx.fd >= 0 && close(ctx.fd)) {
691d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't close the file for the XRC Domain\n");
692d6b92ffaSHans Petter Selasky 		return 1;
693d6b92ffaSHans Petter Selasky 	}
694d6b92ffaSHans Petter Selasky 
695d6b92ffaSHans Petter Selasky 	if (ibv_destroy_cq(ctx.send_cq)) {
696d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't destroy send CQ\n");
697d6b92ffaSHans Petter Selasky 		return 1;
698d6b92ffaSHans Petter Selasky 	}
699d6b92ffaSHans Petter Selasky 
700d6b92ffaSHans Petter Selasky 	if (ibv_destroy_cq(ctx.recv_cq)) {
701d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't destroy recv CQ\n");
702d6b92ffaSHans Petter Selasky 		return 1;
703d6b92ffaSHans Petter Selasky 	}
704d6b92ffaSHans Petter Selasky 
705d6b92ffaSHans Petter Selasky 	if (ibv_dereg_mr(ctx.mr)) {
706d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't deregister MR\n");
707d6b92ffaSHans Petter Selasky 		return 1;
708d6b92ffaSHans Petter Selasky 	}
709d6b92ffaSHans Petter Selasky 
710d6b92ffaSHans Petter Selasky 	if (ibv_dealloc_pd(ctx.pd)) {
711d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't deallocate PD\n");
712d6b92ffaSHans Petter Selasky 		return 1;
713d6b92ffaSHans Petter Selasky 	}
714d6b92ffaSHans Petter Selasky 
715d6b92ffaSHans Petter Selasky 	if (ctx.channel) {
716d6b92ffaSHans Petter Selasky 		if (ibv_destroy_comp_channel(ctx.channel)) {
717d6b92ffaSHans Petter Selasky 			fprintf(stderr,
718d6b92ffaSHans Petter Selasky 				"Couldn't destroy completion channel\n");
719d6b92ffaSHans Petter Selasky 			return 1;
720d6b92ffaSHans Petter Selasky 		}
721d6b92ffaSHans Petter Selasky 	}
722d6b92ffaSHans Petter Selasky 
723d6b92ffaSHans Petter Selasky 	if (ibv_close_device(ctx.context)) {
724d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't release context\n");
725d6b92ffaSHans Petter Selasky 		return 1;
726d6b92ffaSHans Petter Selasky 	}
727d6b92ffaSHans Petter Selasky 
728d6b92ffaSHans Petter Selasky 	free(ctx.buf);
729d6b92ffaSHans Petter Selasky 	free(ctx.rem_dest);
730d6b92ffaSHans Petter Selasky 	free(ctx.send_qp);
731d6b92ffaSHans Petter Selasky 	free(ctx.recv_qp);
732d6b92ffaSHans Petter Selasky 	return 0;
733d6b92ffaSHans Petter Selasky }
734d6b92ffaSHans Petter Selasky 
pp_post_recv(int cnt)735d6b92ffaSHans Petter Selasky static int pp_post_recv(int cnt)
736d6b92ffaSHans Petter Selasky {
737d6b92ffaSHans Petter Selasky 	struct ibv_sge sge;
738d6b92ffaSHans Petter Selasky 	struct ibv_recv_wr wr, *bad_wr;
739d6b92ffaSHans Petter Selasky 
740d6b92ffaSHans Petter Selasky 	sge.addr = (uintptr_t) ctx.buf;
741d6b92ffaSHans Petter Selasky 	sge.length = ctx.size;
742d6b92ffaSHans Petter Selasky 	sge.lkey = ctx.mr->lkey;
743d6b92ffaSHans Petter Selasky 
744d6b92ffaSHans Petter Selasky 	wr.next       = NULL;
745d6b92ffaSHans Petter Selasky 	wr.wr_id      = (uintptr_t) &ctx;
746d6b92ffaSHans Petter Selasky 	wr.sg_list    = &sge;
747d6b92ffaSHans Petter Selasky 	wr.num_sge    = 1;
748d6b92ffaSHans Petter Selasky 
749d6b92ffaSHans Petter Selasky 	while (cnt--) {
750d6b92ffaSHans Petter Selasky 		if (ibv_post_srq_recv(ctx.srq, &wr, &bad_wr)) {
751d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Failed to post receive to SRQ\n");
752d6b92ffaSHans Petter Selasky 			return 1;
753d6b92ffaSHans Petter Selasky 		}
754d6b92ffaSHans Petter Selasky 	}
755d6b92ffaSHans Petter Selasky 	return 0;
756d6b92ffaSHans Petter Selasky }
757d6b92ffaSHans Petter Selasky 
758d6b92ffaSHans Petter Selasky /*
759d6b92ffaSHans Petter Selasky  * Send to each client round robin on each set of xrc send/recv qp.
760d6b92ffaSHans Petter Selasky  * Generate a completion on the last send.
761d6b92ffaSHans Petter Selasky  */
pp_post_send(int index)762d6b92ffaSHans Petter Selasky static int pp_post_send(int index)
763d6b92ffaSHans Petter Selasky {
764d6b92ffaSHans Petter Selasky 	struct ibv_sge sge;
765d6b92ffaSHans Petter Selasky 	struct ibv_send_wr wr, *bad_wr;
766d6b92ffaSHans Petter Selasky 	int qpi;
767d6b92ffaSHans Petter Selasky 
768d6b92ffaSHans Petter Selasky 	sge.addr = (uintptr_t) ctx.buf;
769d6b92ffaSHans Petter Selasky 	sge.length = ctx.size;
770d6b92ffaSHans Petter Selasky 	sge.lkey = ctx.mr->lkey;
771d6b92ffaSHans Petter Selasky 
772d6b92ffaSHans Petter Selasky 	wr.wr_id   = (uintptr_t) index;
773d6b92ffaSHans Petter Selasky 	wr.next    = NULL;
774d6b92ffaSHans Petter Selasky 	wr.sg_list = &sge;
775d6b92ffaSHans Petter Selasky 	wr.num_sge = 1;
776d6b92ffaSHans Petter Selasky 	wr.opcode  = IBV_WR_SEND;
777d6b92ffaSHans Petter Selasky 	wr.qp_type.xrc.remote_srqn = ctx.rem_dest[index].srqn;
778d6b92ffaSHans Petter Selasky 
779d6b92ffaSHans Petter Selasky 	qpi = (index + ctx.rem_dest[index].pp_cnt) % ctx.num_clients;
780d6b92ffaSHans Petter Selasky 	wr.send_flags = (++ctx.rem_dest[index].pp_cnt >= ctx.num_tests) ?
781d6b92ffaSHans Petter Selasky 			IBV_SEND_SIGNALED : 0;
782d6b92ffaSHans Petter Selasky 
783d6b92ffaSHans Petter Selasky 	return ibv_post_send(ctx.send_qp[qpi], &wr, &bad_wr);
784d6b92ffaSHans Petter Selasky }
785d6b92ffaSHans Petter Selasky 
find_qp(int qpn)786d6b92ffaSHans Petter Selasky static int find_qp(int qpn)
787d6b92ffaSHans Petter Selasky {
788d6b92ffaSHans Petter Selasky 	int i;
789d6b92ffaSHans Petter Selasky 
790d6b92ffaSHans Petter Selasky 	if (ctx.num_clients == 1)
791d6b92ffaSHans Petter Selasky 		return 0;
792d6b92ffaSHans Petter Selasky 
793d6b92ffaSHans Petter Selasky 	for (i = 0; i < ctx.num_clients; ++i)
794d6b92ffaSHans Petter Selasky 		if (ctx.recv_qp[i]->qp_num == qpn)
795d6b92ffaSHans Petter Selasky 			return i;
796d6b92ffaSHans Petter Selasky 
797d6b92ffaSHans Petter Selasky 	fprintf(stderr, "Unable to find qp %x\n", qpn);
798d6b92ffaSHans Petter Selasky 	return 0;
799d6b92ffaSHans Petter Selasky }
800d6b92ffaSHans Petter Selasky 
get_cq_event(void)801d6b92ffaSHans Petter Selasky static int get_cq_event(void)
802d6b92ffaSHans Petter Selasky {
803d6b92ffaSHans Petter Selasky 	struct ibv_cq *ev_cq;
804d6b92ffaSHans Petter Selasky 	void          *ev_ctx;
805d6b92ffaSHans Petter Selasky 
806d6b92ffaSHans Petter Selasky 	if (ibv_get_cq_event(ctx.channel, &ev_cq, &ev_ctx)) {
807d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Failed to get cq_event\n");
808d6b92ffaSHans Petter Selasky 		return 1;
809d6b92ffaSHans Petter Selasky 	}
810d6b92ffaSHans Petter Selasky 
811d6b92ffaSHans Petter Selasky 	if (ev_cq != ctx.recv_cq) {
812d6b92ffaSHans Petter Selasky 		fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq);
813d6b92ffaSHans Petter Selasky 		return 1;
814d6b92ffaSHans Petter Selasky 	}
815d6b92ffaSHans Petter Selasky 
816d6b92ffaSHans Petter Selasky 	if (ibv_req_notify_cq(ctx.recv_cq, 0)) {
817d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't request CQ notification\n");
818d6b92ffaSHans Petter Selasky 		return 1;
819d6b92ffaSHans Petter Selasky 	}
820d6b92ffaSHans Petter Selasky 
821d6b92ffaSHans Petter Selasky 	return 0;
822d6b92ffaSHans Petter Selasky }
823d6b92ffaSHans Petter Selasky 
init(void)824d6b92ffaSHans Petter Selasky static void init(void)
825d6b92ffaSHans Petter Selasky {
826d6b92ffaSHans Petter Selasky 	srand48(getpid() * time(NULL));
827d6b92ffaSHans Petter Selasky 
828d6b92ffaSHans Petter Selasky 	ctx.size = 4096;
829d6b92ffaSHans Petter Selasky 	ctx.ib_port = 1;
830d6b92ffaSHans Petter Selasky 	ctx.num_clients  = 1;
831d6b92ffaSHans Petter Selasky 	ctx.num_tests = 5;
832d6b92ffaSHans Petter Selasky 	ctx.mtu = IBV_MTU_2048;
833d6b92ffaSHans Petter Selasky 	ctx.sl = 0;
834d6b92ffaSHans Petter Selasky 	ctx.gidx = -1;
835d6b92ffaSHans Petter Selasky }
836d6b92ffaSHans Petter Selasky 
usage(const char * argv0)837d6b92ffaSHans Petter Selasky static void usage(const char *argv0)
838d6b92ffaSHans Petter Selasky {
839d6b92ffaSHans Petter Selasky 	printf("Usage:\n");
840d6b92ffaSHans Petter Selasky 	printf("  %s            start a server and wait for connection\n", argv0);
841d6b92ffaSHans Petter Selasky 	printf("  %s <host>     connect to server at <host>\n", argv0);
842d6b92ffaSHans Petter Selasky 	printf("\n");
843d6b92ffaSHans Petter Selasky 	printf("Options:\n");
844d6b92ffaSHans Petter Selasky 	printf("  -p, --port=<port>      listen on/connect to port <port> (default 18515)\n");
845d6b92ffaSHans Petter Selasky 	printf("  -d, --ib-dev=<dev>     use IB device <dev> (default first device found)\n");
846d6b92ffaSHans Petter Selasky 	printf("  -i, --ib-port=<port>   use port <port> of IB device (default 1)\n");
847d6b92ffaSHans Petter Selasky 	printf("  -s, --size=<size>      size of message to exchange (default 4096)\n");
848d6b92ffaSHans Petter Selasky 	printf("  -m, --mtu=<size>       path MTU (default 2048)\n");
849d6b92ffaSHans Petter Selasky 	printf("  -c, --clients=<n>      number of clients (on server only, default 1)\n");
850d6b92ffaSHans Petter Selasky 	printf("  -n, --num_tests=<n>    number of tests per client (default 5)\n");
851d6b92ffaSHans Petter Selasky 	printf("  -l, --sl=<sl>          service level value\n");
852d6b92ffaSHans Petter Selasky 	printf("  -e, --events           sleep on CQ events (default poll)\n");
853d6b92ffaSHans Petter Selasky 	printf("  -g, --gid-idx=<gid index> local port gid index\n");
854d6b92ffaSHans Petter Selasky }
855d6b92ffaSHans Petter Selasky 
main(int argc,char * argv[])856d6b92ffaSHans Petter Selasky int main(int argc, char *argv[])
857d6b92ffaSHans Petter Selasky {
858d6b92ffaSHans Petter Selasky 	char          *ib_devname = NULL;
859d6b92ffaSHans Petter Selasky 	char          *servername = NULL;
860d6b92ffaSHans Petter Selasky 	int           port = 18515;
861d6b92ffaSHans Petter Selasky 	int           i, total, cnt = 0;
862d6b92ffaSHans Petter Selasky 	int           ne, qpi, num_cq_events = 0;
863d6b92ffaSHans Petter Selasky 	struct ibv_wc wc;
864d6b92ffaSHans Petter Selasky 
865d6b92ffaSHans Petter Selasky 	init();
866d6b92ffaSHans Petter Selasky 	while (1) {
867d6b92ffaSHans Petter Selasky 		int c;
868d6b92ffaSHans Petter Selasky 
869d6b92ffaSHans Petter Selasky 		static struct option long_options[] = {
870d6b92ffaSHans Petter Selasky 			{ .name = "port",      .has_arg = 1, .val = 'p' },
871d6b92ffaSHans Petter Selasky 			{ .name = "ib-dev",    .has_arg = 1, .val = 'd' },
872d6b92ffaSHans Petter Selasky 			{ .name = "ib-port",   .has_arg = 1, .val = 'i' },
873d6b92ffaSHans Petter Selasky 			{ .name = "size",      .has_arg = 1, .val = 's' },
874d6b92ffaSHans Petter Selasky 			{ .name = "mtu",       .has_arg = 1, .val = 'm' },
875d6b92ffaSHans Petter Selasky 			{ .name = "clients",   .has_arg = 1, .val = 'c' },
876d6b92ffaSHans Petter Selasky 			{ .name = "num_tests", .has_arg = 1, .val = 'n' },
877d6b92ffaSHans Petter Selasky 			{ .name = "sl",        .has_arg = 1, .val = 'l' },
878d6b92ffaSHans Petter Selasky 			{ .name = "events",    .has_arg = 0, .val = 'e' },
879d6b92ffaSHans Petter Selasky 			{ .name = "gid-idx",   .has_arg = 1, .val = 'g' },
880d6b92ffaSHans Petter Selasky 			{}
881d6b92ffaSHans Petter Selasky 		};
882d6b92ffaSHans Petter Selasky 
883d6b92ffaSHans Petter Selasky 		c = getopt_long(argc, argv, "p:d:i:s:m:c:n:l:eg:", long_options,
884d6b92ffaSHans Petter Selasky 				NULL);
885d6b92ffaSHans Petter Selasky 		if (c == -1)
886d6b92ffaSHans Petter Selasky 			break;
887d6b92ffaSHans Petter Selasky 
888d6b92ffaSHans Petter Selasky 		switch (c) {
889d6b92ffaSHans Petter Selasky 		case 'p':
890d6b92ffaSHans Petter Selasky 			port = strtol(optarg, NULL, 0);
891d6b92ffaSHans Petter Selasky 			if (port < 0 || port > 65535) {
892d6b92ffaSHans Petter Selasky 				usage(argv[0]);
893d6b92ffaSHans Petter Selasky 				return 1;
894d6b92ffaSHans Petter Selasky 			}
895d6b92ffaSHans Petter Selasky 			break;
896d6b92ffaSHans Petter Selasky 		case 'd':
897d6b92ffaSHans Petter Selasky 			ib_devname = strdupa(optarg);
898d6b92ffaSHans Petter Selasky 			break;
899d6b92ffaSHans Petter Selasky 		case 'i':
900d6b92ffaSHans Petter Selasky 			ctx.ib_port = strtol(optarg, NULL, 0);
901d6b92ffaSHans Petter Selasky 			if (ctx.ib_port < 0) {
902d6b92ffaSHans Petter Selasky 				usage(argv[0]);
903d6b92ffaSHans Petter Selasky 				return 1;
904d6b92ffaSHans Petter Selasky 			}
905d6b92ffaSHans Petter Selasky 			break;
906d6b92ffaSHans Petter Selasky 		case 's':
907d6b92ffaSHans Petter Selasky 			ctx.size = strtol(optarg, NULL, 0);
908d6b92ffaSHans Petter Selasky 			break;
909d6b92ffaSHans Petter Selasky 		case 'm':
910d6b92ffaSHans Petter Selasky 			ctx.mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0));
911d6b92ffaSHans Petter Selasky 			if (ctx.mtu == 0) {
912d6b92ffaSHans Petter Selasky 				usage(argv[0]);
913d6b92ffaSHans Petter Selasky 				return 1;
914d6b92ffaSHans Petter Selasky 			}
915d6b92ffaSHans Petter Selasky 			break;
916d6b92ffaSHans Petter Selasky 		case 'c':
917d6b92ffaSHans Petter Selasky 			ctx.num_clients = strtol(optarg, NULL, 0);
918d6b92ffaSHans Petter Selasky 			break;
919d6b92ffaSHans Petter Selasky 		case 'n':
920d6b92ffaSHans Petter Selasky 			ctx.num_tests = strtol(optarg, NULL, 0);
921d6b92ffaSHans Petter Selasky 			break;
922d6b92ffaSHans Petter Selasky 		case 'l':
923d6b92ffaSHans Petter Selasky 			ctx.sl = strtol(optarg, NULL, 0);
924d6b92ffaSHans Petter Selasky 			break;
925d6b92ffaSHans Petter Selasky 		case 'g':
926d6b92ffaSHans Petter Selasky 			ctx.gidx = strtol(optarg, NULL, 0);
927d6b92ffaSHans Petter Selasky 			break;
928d6b92ffaSHans Petter Selasky 		case 'e':
929d6b92ffaSHans Petter Selasky 			ctx.use_event = 1;
930d6b92ffaSHans Petter Selasky 			break;
931d6b92ffaSHans Petter Selasky 		default:
932d6b92ffaSHans Petter Selasky 			usage(argv[0]);
933d6b92ffaSHans Petter Selasky 			return 1;
934d6b92ffaSHans Petter Selasky 		}
935d6b92ffaSHans Petter Selasky 	}
936d6b92ffaSHans Petter Selasky 
937d6b92ffaSHans Petter Selasky 	if (optind == argc - 1) {
938d6b92ffaSHans Petter Selasky 		servername = strdupa(argv[optind]);
939d6b92ffaSHans Petter Selasky 		ctx.num_clients = 1;
940d6b92ffaSHans Petter Selasky 	} else if (optind < argc) {
941d6b92ffaSHans Petter Selasky 		usage(argv[0]);
942d6b92ffaSHans Petter Selasky 		return 1;
943d6b92ffaSHans Petter Selasky 	}
944d6b92ffaSHans Petter Selasky 
945d6b92ffaSHans Petter Selasky 	page_size = sysconf(_SC_PAGESIZE);
946d6b92ffaSHans Petter Selasky 
947d6b92ffaSHans Petter Selasky 	if (pp_init_ctx(ib_devname))
948d6b92ffaSHans Petter Selasky 		return 1;
949d6b92ffaSHans Petter Selasky 
950d6b92ffaSHans Petter Selasky 	if (pp_post_recv(ctx.num_clients)) {
951d6b92ffaSHans Petter Selasky 		fprintf(stderr, "Couldn't post receives\n");
952d6b92ffaSHans Petter Selasky 		return 1;
953d6b92ffaSHans Petter Selasky 	}
954d6b92ffaSHans Petter Selasky 
955d6b92ffaSHans Petter Selasky 	if (servername) {
956d6b92ffaSHans Petter Selasky 		if (pp_client_connect(servername, port))
957d6b92ffaSHans Petter Selasky 			return 1;
958d6b92ffaSHans Petter Selasky 	} else {
959d6b92ffaSHans Petter Selasky 		if (pp_server_connect(port))
960d6b92ffaSHans Petter Selasky 			return 1;
961d6b92ffaSHans Petter Selasky 
962d6b92ffaSHans Petter Selasky 		for (i = 0; i < ctx.num_clients; i++)
963d6b92ffaSHans Petter Selasky 			pp_post_send(i);
964d6b92ffaSHans Petter Selasky 	}
965d6b92ffaSHans Petter Selasky 
966d6b92ffaSHans Petter Selasky 	total = ctx.num_clients * ctx.num_tests;
967d6b92ffaSHans Petter Selasky 	while (cnt < total) {
968d6b92ffaSHans Petter Selasky 		if (ctx.use_event) {
969d6b92ffaSHans Petter Selasky 			if (get_cq_event())
970d6b92ffaSHans Petter Selasky 				return 1;
971d6b92ffaSHans Petter Selasky 
972d6b92ffaSHans Petter Selasky 			++num_cq_events;
973d6b92ffaSHans Petter Selasky 		}
974d6b92ffaSHans Petter Selasky 
975d6b92ffaSHans Petter Selasky 		do {
976d6b92ffaSHans Petter Selasky 			ne = ibv_poll_cq(ctx.recv_cq, 1, &wc);
977d6b92ffaSHans Petter Selasky 			if (ne < 0) {
978d6b92ffaSHans Petter Selasky 				fprintf(stderr, "Error polling cq %d\n", ne);
979d6b92ffaSHans Petter Selasky 				return 1;
980d6b92ffaSHans Petter Selasky 			} else if (ne == 0) {
981d6b92ffaSHans Petter Selasky 				break;
982d6b92ffaSHans Petter Selasky 			}
983d6b92ffaSHans Petter Selasky 
984d6b92ffaSHans Petter Selasky 			if (wc.status) {
985d6b92ffaSHans Petter Selasky 				fprintf(stderr, "Work completion error %d\n", wc.status);
986d6b92ffaSHans Petter Selasky 				return 1;
987d6b92ffaSHans Petter Selasky 			}
988d6b92ffaSHans Petter Selasky 
989d6b92ffaSHans Petter Selasky 			pp_post_recv(ne);
990d6b92ffaSHans Petter Selasky 			qpi = find_qp(wc.qp_num);
991d6b92ffaSHans Petter Selasky 			if (ctx.rem_dest[qpi].pp_cnt < ctx.num_tests)
992d6b92ffaSHans Petter Selasky 				pp_post_send(qpi);
993d6b92ffaSHans Petter Selasky 			cnt += ne;
994d6b92ffaSHans Petter Selasky 		} while (ne > 0);
995d6b92ffaSHans Petter Selasky 	}
996d6b92ffaSHans Petter Selasky 
997d6b92ffaSHans Petter Selasky 	for (cnt = 0; cnt < ctx.num_clients; cnt += ne) {
998d6b92ffaSHans Petter Selasky 		ne = ibv_poll_cq(ctx.send_cq, 1, &wc);
999d6b92ffaSHans Petter Selasky 		if (ne < 0) {
1000d6b92ffaSHans Petter Selasky 			fprintf(stderr, "Error polling cq %d\n", ne);
1001d6b92ffaSHans Petter Selasky 			return 1;
1002d6b92ffaSHans Petter Selasky 		}
1003d6b92ffaSHans Petter Selasky 	}
1004d6b92ffaSHans Petter Selasky 
1005d6b92ffaSHans Petter Selasky 	if (ctx.use_event)
1006d6b92ffaSHans Petter Selasky 		ibv_ack_cq_events(ctx.recv_cq, num_cq_events);
1007d6b92ffaSHans Petter Selasky 
1008d6b92ffaSHans Petter Selasky 	/* Process should get an ack from the daemon to close its resources to
1009d6b92ffaSHans Petter Selasky 	  * make sure latest daemon's response sent via its target QP destined
1010d6b92ffaSHans Petter Selasky 	  * to an XSRQ created by another client won't be lost.
1011d6b92ffaSHans Petter Selasky 	  * Failure to do so may cause the other client to wait for that sent
1012d6b92ffaSHans Petter Selasky 	  * message forever. See comment on pp_post_send.
1013d6b92ffaSHans Petter Selasky 	*/
1014d6b92ffaSHans Petter Selasky 	if (servername) {
1015d6b92ffaSHans Petter Selasky 		if (pp_client_termination())
1016d6b92ffaSHans Petter Selasky 			return 1;
1017d6b92ffaSHans Petter Selasky 	} else if (pp_server_termination()) {
1018d6b92ffaSHans Petter Selasky 		return 1;
1019d6b92ffaSHans Petter Selasky 	}
1020d6b92ffaSHans Petter Selasky 
1021d6b92ffaSHans Petter Selasky 	if (pp_close_ctx())
1022d6b92ffaSHans Petter Selasky 		return 1;
1023d6b92ffaSHans Petter Selasky 
1024d6b92ffaSHans Petter Selasky 	printf("success\n");
1025d6b92ffaSHans Petter Selasky 	return 0;
1026d6b92ffaSHans Petter Selasky }
1027