xref: /freebsd/contrib/ofed/libibverbs/examples/srq_pingpong.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
1 /*
2  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 
33 #if HAVE_CONFIG_H
34 #  include <config.h>
35 #endif /* HAVE_CONFIG_H */
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <sys/time.h>
44 #include <netdb.h>
45 #include <getopt.h>
46 #include <arpa/inet.h>
47 #include <time.h>
48 
49 #include "pingpong.h"
50 
51 enum {
52 	PINGPONG_RECV_WRID = 1,
53 	PINGPONG_SEND_WRID = 2,
54 
55 	MAX_QP             = 256,
56 };
57 
58 static int page_size;
59 
60 struct pingpong_context {
61 	struct ibv_context	*context;
62 	struct ibv_comp_channel *channel;
63 	struct ibv_pd		*pd;
64 	struct ibv_mr		*mr;
65 	struct ibv_cq		*cq;
66 	struct ibv_srq		*srq;
67 	struct ibv_qp		*qp[MAX_QP];
68 	void			*buf;
69 	int			 size;
70 	int			 num_qp;
71 	int			 rx_depth;
72 	int			 pending[MAX_QP];
73 	struct ibv_port_attr	 portinfo;
74 };
75 
76 struct pingpong_dest {
77 	int lid;
78 	int qpn;
79 	int psn;
80 	union ibv_gid gid;
81 };
82 
83 static int pp_connect_ctx(struct pingpong_context *ctx, int port, enum ibv_mtu mtu,
84 			  int sl, const struct pingpong_dest *my_dest,
85 			  const struct pingpong_dest *dest, int sgid_idx)
86 {
87 	int i;
88 
89 	for (i = 0; i < ctx->num_qp; ++i) {
90 		struct ibv_qp_attr attr = {
91 			.qp_state		= IBV_QPS_RTR,
92 			.path_mtu		= mtu,
93 			.dest_qp_num		= dest[i].qpn,
94 			.rq_psn			= dest[i].psn,
95 			.max_dest_rd_atomic	= 1,
96 			.min_rnr_timer		= 12,
97 			.ah_attr		= {
98 				.is_global	= 0,
99 				.dlid		= dest[i].lid,
100 				.sl		= sl,
101 				.src_path_bits	= 0,
102 				.port_num	= port
103 			}
104 		};
105 
106 		if (dest->gid.global.interface_id) {
107 			attr.ah_attr.is_global = 1;
108 			attr.ah_attr.grh.hop_limit = 1;
109 			attr.ah_attr.grh.dgid = dest->gid;
110 			attr.ah_attr.grh.sgid_index = sgid_idx;
111 		}
112 		if (ibv_modify_qp(ctx->qp[i], &attr,
113 				  IBV_QP_STATE              |
114 				  IBV_QP_AV                 |
115 				  IBV_QP_PATH_MTU           |
116 				  IBV_QP_DEST_QPN           |
117 				  IBV_QP_RQ_PSN             |
118 				  IBV_QP_MAX_DEST_RD_ATOMIC |
119 				  IBV_QP_MIN_RNR_TIMER)) {
120 			fprintf(stderr, "Failed to modify QP[%d] to RTR\n", i);
121 			return 1;
122 		}
123 
124 		attr.qp_state	    = IBV_QPS_RTS;
125 		attr.timeout	    = 14;
126 		attr.retry_cnt	    = 7;
127 		attr.rnr_retry	    = 7;
128 		attr.sq_psn	    = my_dest[i].psn;
129 		attr.max_rd_atomic  = 1;
130 		if (ibv_modify_qp(ctx->qp[i], &attr,
131 				  IBV_QP_STATE              |
132 				  IBV_QP_TIMEOUT            |
133 				  IBV_QP_RETRY_CNT          |
134 				  IBV_QP_RNR_RETRY          |
135 				  IBV_QP_SQ_PSN             |
136 				  IBV_QP_MAX_QP_RD_ATOMIC)) {
137 			fprintf(stderr, "Failed to modify QP[%d] to RTS\n", i);
138 			return 1;
139 		}
140 	}
141 
142 	return 0;
143 }
144 
145 static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port,
146 						 const struct pingpong_dest *my_dest)
147 {
148 	struct addrinfo *res, *t;
149 	struct addrinfo hints = {
150 		.ai_family   = AF_INET,
151 		.ai_socktype = SOCK_STREAM
152 	};
153 	char *service;
154 	char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"];
155 	int n;
156 	int r;
157 	int i;
158 	int sockfd = -1;
159 	struct pingpong_dest *rem_dest = NULL;
160 	char gid[33];
161 
162 	if (asprintf(&service, "%d", port) < 0)
163 		return NULL;
164 
165 	n = getaddrinfo(servername, service, &hints, &res);
166 
167 	if (n < 0) {
168 		fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port);
169 		free(service);
170 		return NULL;
171 	}
172 
173 	for (t = res; t; t = t->ai_next) {
174 		sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
175 		if (sockfd >= 0) {
176 			if (!connect(sockfd, t->ai_addr, t->ai_addrlen))
177 				break;
178 			close(sockfd);
179 			sockfd = -1;
180 		}
181 	}
182 
183 	freeaddrinfo(res);
184 	free(service);
185 
186 	if (sockfd < 0) {
187 		fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port);
188 		return NULL;
189 	}
190 
191 	for (i = 0; i < MAX_QP; ++i) {
192 		gid_to_wire_gid(&my_dest[i].gid, gid);
193 		sprintf(msg, "%04x:%06x:%06x:%s", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, gid);
194 		if (write(sockfd, msg, sizeof msg) != sizeof msg) {
195 			fprintf(stderr, "Couldn't send local address\n");
196 			goto out;
197 		}
198 	}
199 
200 	rem_dest = malloc(MAX_QP * sizeof *rem_dest);
201 	if (!rem_dest)
202 		goto out;
203 
204 	for (i = 0; i < MAX_QP; ++i) {
205 		n = 0;
206 		while (n < sizeof msg) {
207 			r = read(sockfd, msg + n, sizeof msg - n);
208 			if (r < 0) {
209 				perror("client read");
210 				fprintf(stderr, "%d/%d: Couldn't read remote address [%d]\n",
211 					n, (int) sizeof msg, i);
212 				goto out;
213 			}
214 			n += r;
215 		}
216 
217 		sscanf(msg, "%x:%x:%x:%s",
218 		       &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn, gid);
219 		wire_gid_to_gid(gid, &rem_dest[i].gid);
220 	}
221 
222 	write(sockfd, "done", sizeof "done");
223 
224 out:
225 	close(sockfd);
226 	return rem_dest;
227 }
228 
229 static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx,
230 						 int ib_port, enum ibv_mtu mtu,
231 						 int port, int sl,
232 						 const struct pingpong_dest *my_dest,
233 						 int sgid_idx)
234 {
235 	struct addrinfo *res, *t;
236 	struct addrinfo hints = {
237 		.ai_flags    = AI_PASSIVE,
238 		.ai_family   = AF_INET,
239 		.ai_socktype = SOCK_STREAM
240 	};
241 	char *service;
242 	char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"];
243 	int n;
244 	int r;
245 	int i;
246 	int sockfd = -1, connfd;
247 	struct pingpong_dest *rem_dest = NULL;
248 	char gid[33];
249 
250 	if (asprintf(&service, "%d", port) < 0)
251 		return NULL;
252 
253 	n = getaddrinfo(NULL, service, &hints, &res);
254 
255 	if (n < 0) {
256 		fprintf(stderr, "%s for port %d\n", gai_strerror(n), port);
257 		free(service);
258 		return NULL;
259 	}
260 
261 	for (t = res; t; t = t->ai_next) {
262 		sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
263 		if (sockfd >= 0) {
264 			n = 1;
265 
266 			setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n);
267 
268 			if (!bind(sockfd, t->ai_addr, t->ai_addrlen))
269 				break;
270 			close(sockfd);
271 			sockfd = -1;
272 		}
273 	}
274 
275 	freeaddrinfo(res);
276 	free(service);
277 
278 	if (sockfd < 0) {
279 		fprintf(stderr, "Couldn't listen to port %d\n", port);
280 		return NULL;
281 	}
282 
283 	listen(sockfd, 1);
284 	connfd = accept(sockfd, NULL, 0);
285 	close(sockfd);
286 	if (connfd < 0) {
287 		fprintf(stderr, "accept() failed\n");
288 		return NULL;
289 	}
290 
291 	rem_dest = malloc(MAX_QP * sizeof *rem_dest);
292 	if (!rem_dest)
293 		goto out;
294 
295 	for (i = 0; i < MAX_QP; ++i) {
296 		n = 0;
297 		while (n < sizeof msg) {
298 			r = read(connfd, msg + n, sizeof msg - n);
299 			if (r < 0) {
300 				perror("server read");
301 				fprintf(stderr, "%d/%d: Couldn't read remote address [%d]\n",
302 					n, (int) sizeof msg, i);
303 				goto out;
304 			}
305 			n += r;
306 		}
307 
308 		sscanf(msg, "%x:%x:%x:%s",
309 		       &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn, gid);
310 		wire_gid_to_gid(gid, &rem_dest[i].gid);
311 	}
312 
313 	if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest, sgid_idx)) {
314 		fprintf(stderr, "Couldn't connect to remote QP\n");
315 		free(rem_dest);
316 		rem_dest = NULL;
317 		goto out;
318 	}
319 
320 	for (i = 0; i < MAX_QP; ++i) {
321 		gid_to_wire_gid(&my_dest[i].gid, gid);
322 		sprintf(msg, "%04x:%06x:%06x:%s", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, gid);
323 		if (write(connfd, msg, sizeof msg) != sizeof msg) {
324 			fprintf(stderr, "Couldn't send local address\n");
325 			free(rem_dest);
326 			rem_dest = NULL;
327 			goto out;
328 		}
329 	}
330 
331 	read(connfd, msg, sizeof msg);
332 
333 out:
334 	close(connfd);
335 	return rem_dest;
336 }
337 
338 static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
339 					    int num_qp, int rx_depth, int port,
340 					    int use_event)
341 {
342 	struct pingpong_context *ctx;
343 	int i;
344 
345 	ctx = calloc(1, sizeof *ctx);
346 	if (!ctx)
347 		return NULL;
348 
349 	ctx->size     = size;
350 	ctx->num_qp   = num_qp;
351 	ctx->rx_depth = rx_depth;
352 
353 	ctx->buf = malloc(roundup(size, page_size));
354 	if (!ctx->buf) {
355 		fprintf(stderr, "Couldn't allocate work buf.\n");
356 		return NULL;
357 	}
358 
359 	memset(ctx->buf, 0, size);
360 
361 	ctx->context = ibv_open_device(ib_dev);
362 	if (!ctx->context) {
363 		fprintf(stderr, "Couldn't get context for %s\n",
364 			ibv_get_device_name(ib_dev));
365 		return NULL;
366 	}
367 
368 	if (use_event) {
369 		ctx->channel = ibv_create_comp_channel(ctx->context);
370 		if (!ctx->channel) {
371 			fprintf(stderr, "Couldn't create completion channel\n");
372 			return NULL;
373 		}
374 	} else
375 		ctx->channel = NULL;
376 
377 	ctx->pd = ibv_alloc_pd(ctx->context);
378 	if (!ctx->pd) {
379 		fprintf(stderr, "Couldn't allocate PD\n");
380 		return NULL;
381 	}
382 
383 	ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE);
384 	if (!ctx->mr) {
385 		fprintf(stderr, "Couldn't register MR\n");
386 		return NULL;
387 	}
388 
389 	ctx->cq = ibv_create_cq(ctx->context, rx_depth + num_qp, NULL,
390 				ctx->channel, 0);
391 	if (!ctx->cq) {
392 		fprintf(stderr, "Couldn't create CQ\n");
393 		return NULL;
394 	}
395 
396 	{
397 		struct ibv_srq_init_attr attr = {
398 			.attr = {
399 				.max_wr  = rx_depth,
400 				.max_sge = 1
401 			}
402 		};
403 
404 		ctx->srq = ibv_create_srq(ctx->pd, &attr);
405 		if (!ctx->srq)  {
406 			fprintf(stderr, "Couldn't create SRQ\n");
407 			return NULL;
408 		}
409 	}
410 
411 	for (i = 0; i < num_qp; ++i) {
412 		struct ibv_qp_init_attr attr = {
413 			.send_cq = ctx->cq,
414 			.recv_cq = ctx->cq,
415 			.srq     = ctx->srq,
416 			.cap     = {
417 				.max_send_wr  = 1,
418 				.max_send_sge = 1,
419 			},
420 			.qp_type = IBV_QPT_RC
421 		};
422 
423 		ctx->qp[i] = ibv_create_qp(ctx->pd, &attr);
424 		if (!ctx->qp[i])  {
425 			fprintf(stderr, "Couldn't create QP[%d]\n", i);
426 			return NULL;
427 		}
428 	}
429 
430 	for (i = 0; i < num_qp; ++i) {
431 		struct ibv_qp_attr attr = {
432 			.qp_state        = IBV_QPS_INIT,
433 			.pkey_index      = 0,
434 			.port_num        = port,
435 			.qp_access_flags = 0
436 		};
437 
438 		if (ibv_modify_qp(ctx->qp[i], &attr,
439 				  IBV_QP_STATE              |
440 				  IBV_QP_PKEY_INDEX         |
441 				  IBV_QP_PORT               |
442 				  IBV_QP_ACCESS_FLAGS)) {
443 			fprintf(stderr, "Failed to modify QP[%d] to INIT\n", i);
444 			return NULL;
445 		}
446 	}
447 
448 	return ctx;
449 }
450 
451 int pp_close_ctx(struct pingpong_context *ctx, int num_qp)
452 {
453 	int i;
454 
455 	for (i = 0; i < num_qp; ++i) {
456 		if (ibv_destroy_qp(ctx->qp[i])) {
457 			fprintf(stderr, "Couldn't destroy QP[%d]\n", i);
458 			return 1;
459 		}
460 	}
461 
462 	if (ibv_destroy_srq(ctx->srq)) {
463 		fprintf(stderr, "Couldn't destroy SRQ\n");
464 		return 1;
465 	}
466 
467 	if (ibv_destroy_cq(ctx->cq)) {
468 		fprintf(stderr, "Couldn't destroy CQ\n");
469 		return 1;
470 	}
471 
472 	if (ibv_dereg_mr(ctx->mr)) {
473 		fprintf(stderr, "Couldn't deregister MR\n");
474 		return 1;
475 	}
476 
477 	if (ibv_dealloc_pd(ctx->pd)) {
478 		fprintf(stderr, "Couldn't deallocate PD\n");
479 		return 1;
480 	}
481 
482 	if (ctx->channel) {
483 		if (ibv_destroy_comp_channel(ctx->channel)) {
484 			fprintf(stderr, "Couldn't destroy completion channel\n");
485 			return 1;
486 		}
487 	}
488 
489 	if (ibv_close_device(ctx->context)) {
490 		fprintf(stderr, "Couldn't release context\n");
491 		return 1;
492 	}
493 
494 	free(ctx->buf);
495 	free(ctx);
496 
497 	return 0;
498 }
499 
500 static int pp_post_recv(struct pingpong_context *ctx, int n)
501 {
502 	struct ibv_sge list = {
503 		.addr	= (uintptr_t) ctx->buf,
504 		.length = ctx->size,
505 		.lkey	= ctx->mr->lkey
506 	};
507 	struct ibv_recv_wr wr = {
508 		.wr_id	    = PINGPONG_RECV_WRID,
509 		.sg_list    = &list,
510 		.num_sge    = 1,
511 	};
512 	struct ibv_recv_wr *bad_wr;
513 	int i;
514 
515 	for (i = 0; i < n; ++i)
516 		if (ibv_post_srq_recv(ctx->srq, &wr, &bad_wr))
517 			break;
518 
519 	return i;
520 }
521 
522 static int pp_post_send(struct pingpong_context *ctx, int qp_index)
523 {
524 	struct ibv_sge list = {
525 		.addr	= (uintptr_t) ctx->buf,
526 		.length = ctx->size,
527 		.lkey	= ctx->mr->lkey
528 	};
529 	struct ibv_send_wr wr = {
530 		.wr_id	    = PINGPONG_SEND_WRID,
531 		.sg_list    = &list,
532 		.num_sge    = 1,
533 		.opcode     = IBV_WR_SEND,
534 		.send_flags = IBV_SEND_SIGNALED,
535 	};
536 	struct ibv_send_wr *bad_wr;
537 
538 	return ibv_post_send(ctx->qp[qp_index], &wr, &bad_wr);
539 }
540 
541 static int find_qp(int qpn, struct pingpong_context *ctx, int num_qp)
542 {
543 	int i;
544 
545 	for (i = 0; i < num_qp; ++i)
546 		if (ctx->qp[i]->qp_num == qpn)
547 			return i;
548 
549 	return -1;
550 }
551 
552 static void usage(const char *argv0)
553 {
554 	printf("Usage:\n");
555 	printf("  %s            start a server and wait for connection\n", argv0);
556 	printf("  %s <host>     connect to server at <host>\n", argv0);
557 	printf("\n");
558 	printf("Options:\n");
559 	printf("  -p, --port=<port>      listen on/connect to port <port> (default 18515)\n");
560 	printf("  -d, --ib-dev=<dev>     use IB device <dev> (default first device found)\n");
561 	printf("  -i, --ib-port=<port>   use port <port> of IB device (default 1)\n");
562 	printf("  -s, --size=<size>      size of message to exchange (default 4096)\n");
563 	printf("  -m, --mtu=<size>       path MTU (default 1024)\n");
564 	printf("  -q, --num-qp=<num>     number of QPs to use (default 16)\n");
565 	printf("  -r, --rx-depth=<dep>   number of receives to post at a time (default 500)\n");
566 	printf("  -n, --iters=<iters>    number of exchanges per QP(default 1000)\n");
567 	printf("  -l, --sl=<sl>          service level value\n");
568 	printf("  -e, --events           sleep on CQ events (default poll)\n");
569 	printf("  -g, --gid-idx=<gid index> local port gid index\n");
570 }
571 
572 int main(int argc, char *argv[])
573 {
574 	struct ibv_device      **dev_list;
575 	struct ibv_device	*ib_dev;
576 	struct ibv_wc		*wc;
577 	struct pingpong_context *ctx;
578 	struct pingpong_dest     my_dest[MAX_QP];
579 	struct pingpong_dest    *rem_dest;
580 	struct timeval           start, end;
581 	char                    *ib_devname = NULL;
582 	char                    *servername = NULL;
583 	int                      port = 18515;
584 	int                      ib_port = 1;
585 	int                      size = 4096;
586 	enum ibv_mtu		 mtu = IBV_MTU_1024;
587 	int                      num_qp = 16;
588 	int                      rx_depth = 500;
589 	int                      iters = 1000;
590 	int                      use_event = 0;
591 	int                      routs;
592 	int                      rcnt, scnt;
593 	int			 num_wc;
594 	int                      i;
595 	int                      num_cq_events = 0;
596 	int                      sl = 0;
597 	int			 gidx = -1;
598 	char			 gid[33];
599 
600 	srand48(getpid() * time(NULL));
601 
602 	while (1) {
603 		int c;
604 
605 		static struct option long_options[] = {
606 			{ .name = "port",     .has_arg = 1, .val = 'p' },
607 			{ .name = "ib-dev",   .has_arg = 1, .val = 'd' },
608 			{ .name = "ib-port",  .has_arg = 1, .val = 'i' },
609 			{ .name = "size",     .has_arg = 1, .val = 's' },
610 			{ .name = "mtu",      .has_arg = 1, .val = 'm' },
611 			{ .name = "num-qp",   .has_arg = 1, .val = 'q' },
612 			{ .name = "rx-depth", .has_arg = 1, .val = 'r' },
613 			{ .name = "iters",    .has_arg = 1, .val = 'n' },
614 			{ .name = "sl",       .has_arg = 1, .val = 'l' },
615 			{ .name = "events",   .has_arg = 0, .val = 'e' },
616 			{ .name = "gid-idx",  .has_arg = 1, .val = 'g' },
617 			{ 0 }
618 		};
619 
620 		c = getopt_long(argc, argv, "p:d:i:s:m:q:r:n:l:eg:", long_options, NULL);
621 		if (c == -1)
622 			break;
623 
624 		switch (c) {
625 		case 'p':
626 			port = strtol(optarg, NULL, 0);
627 			if (port < 0 || port > 65535) {
628 				usage(argv[0]);
629 				return 1;
630 			}
631 			break;
632 
633 		case 'd':
634 			ib_devname = strdup(optarg);
635 			break;
636 
637 		case 'i':
638 			ib_port = strtol(optarg, NULL, 0);
639 			if (ib_port < 0) {
640 				usage(argv[0]);
641 				return 1;
642 			}
643 			break;
644 
645 		case 's':
646 			size = strtol(optarg, NULL, 0);
647 			break;
648 
649 		case 'm':
650 			mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0));
651 			if (mtu < 0) {
652 				usage(argv[0]);
653 				return 1;
654 			}
655 			break;
656 
657 		case 'q':
658 			num_qp = strtol(optarg, NULL, 0);
659 			break;
660 
661 		case 'r':
662 			rx_depth = strtol(optarg, NULL, 0);
663 			break;
664 
665 		case 'n':
666 			iters = strtol(optarg, NULL, 0);
667 			break;
668 
669 		case 'l':
670 			sl = strtol(optarg, NULL, 0);
671 			break;
672 
673 		case 'e':
674 			++use_event;
675 			break;
676 
677 		case 'g':
678 			gidx = strtol(optarg, NULL, 0);
679 			break;
680 
681 		default:
682 			usage(argv[0]);
683 			return 1;
684 		}
685 	}
686 
687 	if (optind == argc - 1)
688 		servername = strdup(argv[optind]);
689 	else if (optind < argc) {
690 		usage(argv[0]);
691 		return 1;
692 	}
693 
694 	if (num_qp > rx_depth) {
695 		fprintf(stderr, "rx_depth %d is too small for %d QPs -- "
696 			"must have at least one receive per QP.\n",
697 			rx_depth, num_qp);
698 		return 1;
699 	}
700 
701 	num_wc = num_qp + rx_depth;
702 	wc     = alloca(num_wc * sizeof *wc);
703 
704 	page_size = sysconf(_SC_PAGESIZE);
705 
706 	dev_list = ibv_get_device_list(NULL);
707 	if (!dev_list) {
708 		perror("Failed to get IB devices list");
709 		return 1;
710 	}
711 
712 	if (!ib_devname) {
713 		ib_dev = *dev_list;
714 		if (!ib_dev) {
715 			fprintf(stderr, "No IB devices found\n");
716 			return 1;
717 		}
718 	} else {
719 		int i;
720 		for (i = 0; dev_list[i]; ++i)
721 			if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname))
722 				break;
723 		ib_dev = dev_list[i];
724 		if (!ib_dev) {
725 			fprintf(stderr, "IB device %s not found\n", ib_devname);
726 			return 1;
727 		}
728 	}
729 
730 	ctx = pp_init_ctx(ib_dev, size, num_qp, rx_depth, ib_port, use_event);
731 	if (!ctx)
732 		return 1;
733 
734 	routs = pp_post_recv(ctx, ctx->rx_depth);
735 	if (routs < ctx->rx_depth) {
736 		fprintf(stderr, "Couldn't post receive (%d)\n", routs);
737 		return 1;
738 	}
739 
740 	if (use_event)
741 		if (ibv_req_notify_cq(ctx->cq, 0)) {
742 			fprintf(stderr, "Couldn't request CQ notification\n");
743 			return 1;
744 		}
745 
746 	memset(my_dest, 0, sizeof my_dest);
747 
748 	if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) {
749 		fprintf(stderr, "Couldn't get port info\n");
750 		return 1;
751 	}
752 	for (i = 0; i < num_qp; ++i) {
753 		my_dest[i].qpn = ctx->qp[i]->qp_num;
754 		my_dest[i].psn = lrand48() & 0xffffff;
755 		my_dest[i].lid = ctx->portinfo.lid;
756 		if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest[i].lid) {
757 			fprintf(stderr, "Couldn't get local LID\n");
758 			return 1;
759 		}
760 
761 		if (gidx >= 0) {
762 			if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest[i].gid)) {
763 				fprintf(stderr, "Could not get local gid for gid index %d\n", gidx);
764 				return 1;
765 			}
766 		} else
767 			memset(&my_dest[i].gid, 0, sizeof my_dest[i].gid);
768 
769 		inet_ntop(AF_INET6, &my_dest[i].gid, gid, sizeof gid);
770 		printf("  local address:  LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n",
771 		       my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, gid);
772 	}
773 
774 	if (servername)
775 		rem_dest = pp_client_exch_dest(servername, port, my_dest);
776 	else
777 		rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, my_dest, gidx);
778 
779 	if (!rem_dest)
780 		return 1;
781 
782 	inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid);
783 
784 	for (i = 0; i < num_qp; ++i) {
785 		inet_ntop(AF_INET6, &rem_dest[i].gid, gid, sizeof gid);
786 		printf("  remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n",
787 		       rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn, gid);
788 	}
789 
790 	if (servername)
791 		if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest, gidx))
792 			return 1;
793 
794 	if (servername)
795 		for (i = 0; i < num_qp; ++i) {
796 			if (pp_post_send(ctx, i)) {
797 				fprintf(stderr, "Couldn't post send\n");
798 				return 1;
799 			}
800 			ctx->pending[i] = PINGPONG_SEND_WRID | PINGPONG_RECV_WRID;
801 		}
802 	else
803 		for (i = 0; i < num_qp; ++i)
804 			ctx->pending[i] = PINGPONG_RECV_WRID;
805 
806 	if (gettimeofday(&start, NULL)) {
807 		perror("gettimeofday");
808 		return 1;
809 	}
810 
811 	rcnt = scnt = 0;
812 	while (rcnt < iters || scnt < iters) {
813 		if (use_event) {
814 			struct ibv_cq *ev_cq;
815 			void          *ev_ctx;
816 
817 			if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) {
818 				fprintf(stderr, "Failed to get cq_event\n");
819 				return 1;
820 			}
821 
822 			++num_cq_events;
823 
824 			if (ev_cq != ctx->cq) {
825 				fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq);
826 				return 1;
827 			}
828 
829 			if (ibv_req_notify_cq(ctx->cq, 0)) {
830 				fprintf(stderr, "Couldn't request CQ notification\n");
831 				return 1;
832 			}
833 		}
834 
835 		{
836 			int ne, qp_ind;
837 
838 			do {
839 				ne = ibv_poll_cq(ctx->cq, num_wc, wc);
840 				if (ne < 0) {
841 					fprintf(stderr, "poll CQ failed %d\n", ne);
842 					return 1;
843 				}
844 			} while (!use_event && ne < 1);
845 
846 			for (i = 0; i < ne; ++i) {
847 				if (wc[i].status != IBV_WC_SUCCESS) {
848 					fprintf(stderr, "Failed status %s (%d) for wr_id %d\n",
849 						ibv_wc_status_str(wc[i].status),
850 						wc[i].status, (int) wc[i].wr_id);
851 					return 1;
852 				}
853 
854 				qp_ind = find_qp(wc[i].qp_num, ctx, num_qp);
855 				if (qp_ind < 0) {
856 					fprintf(stderr, "Couldn't find QPN %06x\n",
857 						wc[i].qp_num);
858 					return 1;
859 				}
860 
861 				switch ((int) wc[i].wr_id) {
862 				case PINGPONG_SEND_WRID:
863 					++scnt;
864 					break;
865 
866 				case PINGPONG_RECV_WRID:
867 					if (--routs <= num_qp) {
868 						routs += pp_post_recv(ctx, ctx->rx_depth - routs);
869 						if (routs < ctx->rx_depth) {
870 							fprintf(stderr,
871 								"Couldn't post receive (%d)\n",
872 								routs);
873 							return 1;
874 						}
875 					}
876 
877 					++rcnt;
878 					break;
879 
880 				default:
881 					fprintf(stderr, "Completion for unknown wr_id %d\n",
882 						(int) wc[i].wr_id);
883 					return 1;
884 				}
885 
886 				ctx->pending[qp_ind] &= ~(int) wc[i].wr_id;
887 				if (scnt < iters && !ctx->pending[qp_ind]) {
888 					if (pp_post_send(ctx, qp_ind)) {
889 						fprintf(stderr, "Couldn't post send\n");
890 						return 1;
891 					}
892 					ctx->pending[qp_ind] = PINGPONG_RECV_WRID |
893 							       PINGPONG_SEND_WRID;
894 				}
895 
896 			}
897 		}
898 	}
899 
900 	if (gettimeofday(&end, NULL)) {
901 		perror("gettimeofday");
902 		return 1;
903 	}
904 
905 	{
906 		float usec = (end.tv_sec - start.tv_sec) * 1000000 +
907 			(end.tv_usec - start.tv_usec);
908 		long long bytes = (long long) size * iters * 2;
909 
910 		printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n",
911 		       bytes, usec / 1000000., bytes * 8. / usec);
912 		printf("%d iters in %.2f seconds = %.2f usec/iter\n",
913 		       iters, usec / 1000000., usec / iters);
914 	}
915 
916 	ibv_ack_cq_events(ctx->cq, num_cq_events);
917 
918 	if (pp_close_ctx(ctx, num_qp))
919 		return 1;
920 
921 	ibv_free_device_list(dev_list);
922 	free(rem_dest);
923 
924 	return 0;
925 }
926