]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/libibverbs/examples/srq_pingpong.c
MFV r337818:
[FreeBSD/FreeBSD.git] / contrib / ofed / libibverbs / examples / srq_pingpong.c
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 #define _GNU_SOURCE
33 #include <config.h>
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/time.h>
42 #include <netdb.h>
43 #include <stdlib.h>
44 #include <getopt.h>
45 #include <arpa/inet.h>
46 #include <time.h>
47
48 #include "pingpong.h"
49
50 enum {
51         PINGPONG_RECV_WRID = 1,
52         PINGPONG_SEND_WRID = 2,
53
54         MAX_QP             = 256,
55 };
56
57 static int page_size;
58
59 struct pingpong_context {
60         struct ibv_context      *context;
61         struct ibv_comp_channel *channel;
62         struct ibv_pd           *pd;
63         struct ibv_mr           *mr;
64         struct ibv_cq           *cq;
65         struct ibv_srq          *srq;
66         struct ibv_qp           *qp[MAX_QP];
67         void                    *buf;
68         int                      size;
69         int                      send_flags;
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_UNSPEC,
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_null(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,
194                                         my_dest[i].qpn, my_dest[i].psn, gid);
195                 if (write(sockfd, msg, sizeof msg) != sizeof msg) {
196                         fprintf(stderr, "Couldn't send local address\n");
197                         goto out;
198                 }
199         }
200
201         rem_dest = malloc(MAX_QP * sizeof *rem_dest);
202         if (!rem_dest)
203                 goto out;
204
205         for (i = 0; i < MAX_QP; ++i) {
206                 n = 0;
207                 while (n < sizeof msg) {
208                         r = read(sockfd, msg + n, sizeof msg - n);
209                         if (r < 0) {
210                                 perror("client read");
211                                 fprintf(stderr, "%d/%d: Couldn't read remote address [%d]\n",
212                                         n, (int) sizeof msg, i);
213                                 goto out;
214                         }
215                         n += r;
216                 }
217
218                 sscanf(msg, "%x:%x:%x:%s", &rem_dest[i].lid, &rem_dest[i].qpn,
219                                                         &rem_dest[i].psn, gid);
220                 wire_gid_to_gid(gid, &rem_dest[i].gid);
221         }
222
223         if (write(sockfd, "done", sizeof "done") != sizeof "done") {
224                 perror("client write");
225                 goto out;
226         }
227 out:
228         close(sockfd);
229         return rem_dest;
230 }
231
232 static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx,
233                                                  int ib_port, enum ibv_mtu mtu,
234                                                  int port, int sl,
235                                                  const struct pingpong_dest *my_dest,
236                                                  int sgid_idx)
237 {
238         struct addrinfo *res, *t;
239         struct addrinfo hints = {
240                 .ai_flags    = AI_PASSIVE,
241                 .ai_family   = AF_INET,
242                 .ai_socktype = SOCK_STREAM
243         };
244         char *service;
245         char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"];
246         int n;
247         int r;
248         int i;
249         int sockfd = -1, connfd;
250         struct pingpong_dest *rem_dest = NULL;
251         char gid[33];
252
253         if (asprintf(&service, "%d", port) < 0)
254                 return NULL;
255
256         n = getaddrinfo(NULL, service, &hints, &res);
257
258         if (n < 0) {
259                 fprintf(stderr, "%s for port %d\n", gai_strerror(n), port);
260                 free(service);
261                 return NULL;
262         }
263
264         for (t = res; t; t = t->ai_next) {
265                 sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol);
266                 if (sockfd >= 0) {
267                         n = 1;
268
269                         setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n);
270
271                         if (!bind(sockfd, t->ai_addr, t->ai_addrlen))
272                                 break;
273                         close(sockfd);
274                         sockfd = -1;
275                 }
276         }
277
278         freeaddrinfo_null(res);
279         free(service);
280
281         if (sockfd < 0) {
282                 fprintf(stderr, "Couldn't listen to port %d\n", port);
283                 return NULL;
284         }
285
286         listen(sockfd, 1);
287         connfd = accept(sockfd, NULL, NULL);
288         close(sockfd);
289         if (connfd < 0) {
290                 fprintf(stderr, "accept() failed\n");
291                 return NULL;
292         }
293
294         rem_dest = malloc(MAX_QP * sizeof *rem_dest);
295         if (!rem_dest)
296                 goto out;
297
298         for (i = 0; i < MAX_QP; ++i) {
299                 n = 0;
300                 while (n < sizeof msg) {
301                         r = read(connfd, msg + n, sizeof msg - n);
302                         if (r < 0) {
303                                 perror("server read");
304                                 fprintf(stderr, "%d/%d: Couldn't read remote address [%d]\n",
305                                         n, (int) sizeof msg, i);
306                                 goto out;
307                         }
308                         n += r;
309                 }
310
311                 sscanf(msg, "%x:%x:%x:%s", &rem_dest[i].lid, &rem_dest[i].qpn,
312                                                         &rem_dest[i].psn, gid);
313                 wire_gid_to_gid(gid, &rem_dest[i].gid);
314         }
315
316         if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest,
317                                                                 sgid_idx)) {
318                 fprintf(stderr, "Couldn't connect to remote QP\n");
319                 free(rem_dest);
320                 rem_dest = NULL;
321                 goto out;
322         }
323
324         for (i = 0; i < MAX_QP; ++i) {
325                 gid_to_wire_gid(&my_dest[i].gid, gid);
326                 sprintf(msg, "%04x:%06x:%06x:%s", my_dest[i].lid,
327                                         my_dest[i].qpn, my_dest[i].psn, gid);
328                 if (write(connfd, msg, sizeof msg) != sizeof msg) {
329                         fprintf(stderr, "Couldn't send local address\n");
330                         free(rem_dest);
331                         rem_dest = NULL;
332                         goto out;
333                 }
334         }
335
336         if (read(connfd, msg, sizeof msg) != sizeof "done") {
337                 perror("client write");
338                 free(rem_dest);
339                 rem_dest = NULL;
340                 goto out;
341         }
342
343 out:
344         close(connfd);
345         return rem_dest;
346 }
347
348 static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size,
349                                             int num_qp, int rx_depth, int port,
350                                             int use_event)
351 {
352         struct pingpong_context *ctx;
353         int i;
354
355         ctx = calloc(1, sizeof *ctx);
356         if (!ctx)
357                 return NULL;
358
359         ctx->size       = size;
360         ctx->send_flags = IBV_SEND_SIGNALED;
361         ctx->num_qp     = num_qp;
362         ctx->rx_depth   = rx_depth;
363
364         ctx->buf = memalign(page_size, size);
365         if (!ctx->buf) {
366                 fprintf(stderr, "Couldn't allocate work buf.\n");
367                 goto clean_ctx;
368         }
369
370         memset(ctx->buf, 0, size);
371
372         ctx->context = ibv_open_device(ib_dev);
373         if (!ctx->context) {
374                 fprintf(stderr, "Couldn't get context for %s\n",
375                         ibv_get_device_name(ib_dev));
376                 goto clean_buffer;
377         }
378
379         if (use_event) {
380                 ctx->channel = ibv_create_comp_channel(ctx->context);
381                 if (!ctx->channel) {
382                         fprintf(stderr, "Couldn't create completion channel\n");
383                         goto clean_device;
384                 }
385         } else
386                 ctx->channel = NULL;
387
388         ctx->pd = ibv_alloc_pd(ctx->context);
389         if (!ctx->pd) {
390                 fprintf(stderr, "Couldn't allocate PD\n");
391                 goto clean_comp_channel;
392         }
393
394         ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE);
395         if (!ctx->mr) {
396                 fprintf(stderr, "Couldn't register MR\n");
397                 goto clean_pd;
398         }
399
400         ctx->cq = ibv_create_cq(ctx->context, rx_depth + num_qp, NULL,
401                                 ctx->channel, 0);
402         if (!ctx->cq) {
403                 fprintf(stderr, "Couldn't create CQ\n");
404                 goto clean_mr;
405         }
406
407         {
408                 struct ibv_srq_init_attr attr = {
409                         .attr = {
410                                 .max_wr  = rx_depth,
411                                 .max_sge = 1
412                         }
413                 };
414
415                 ctx->srq = ibv_create_srq(ctx->pd, &attr);
416                 if (!ctx->srq)  {
417                         fprintf(stderr, "Couldn't create SRQ\n");
418                         goto clean_cq;
419                 }
420         }
421
422         for (i = 0; i < num_qp; ++i) {
423                 struct ibv_qp_attr attr;
424                 struct ibv_qp_init_attr init_attr = {
425                         .send_cq = ctx->cq,
426                         .recv_cq = ctx->cq,
427                         .srq     = ctx->srq,
428                         .cap     = {
429                                 .max_send_wr  = 1,
430                                 .max_send_sge = 1,
431                         },
432                         .qp_type = IBV_QPT_RC
433                 };
434
435                 ctx->qp[i] = ibv_create_qp(ctx->pd, &init_attr);
436                 if (!ctx->qp[i])  {
437                         fprintf(stderr, "Couldn't create QP[%d]\n", i);
438                         goto clean_qps;
439                 }
440                 ibv_query_qp(ctx->qp[i], &attr, IBV_QP_CAP, &init_attr);
441                 if (init_attr.cap.max_inline_data >= size) {
442                         ctx->send_flags |= IBV_SEND_INLINE;
443                 }
444         }
445
446         for (i = 0; i < num_qp; ++i) {
447                 struct ibv_qp_attr attr = {
448                         .qp_state        = IBV_QPS_INIT,
449                         .pkey_index      = 0,
450                         .port_num        = port,
451                         .qp_access_flags = 0
452                 };
453
454                 if (ibv_modify_qp(ctx->qp[i], &attr,
455                                   IBV_QP_STATE              |
456                                   IBV_QP_PKEY_INDEX         |
457                                   IBV_QP_PORT               |
458                                   IBV_QP_ACCESS_FLAGS)) {
459                         fprintf(stderr, "Failed to modify QP[%d] to INIT\n", i);
460                         goto clean_qps_full;
461                 }
462         }
463
464         return ctx;
465
466 clean_qps_full:
467         i = num_qp;
468
469 clean_qps:
470         for (--i; i >= 0; --i)
471                 ibv_destroy_qp(ctx->qp[i]);
472
473         ibv_destroy_srq(ctx->srq);
474
475 clean_cq:
476         ibv_destroy_cq(ctx->cq);
477
478 clean_mr:
479         ibv_dereg_mr(ctx->mr);
480
481 clean_pd:
482         ibv_dealloc_pd(ctx->pd);
483
484 clean_comp_channel:
485         if (ctx->channel)
486                 ibv_destroy_comp_channel(ctx->channel);
487
488 clean_device:
489         ibv_close_device(ctx->context);
490
491 clean_buffer:
492         free(ctx->buf);
493
494 clean_ctx:
495         free(ctx);
496
497         return NULL;
498 }
499
500 static int pp_close_ctx(struct pingpong_context *ctx, int num_qp)
501 {
502         int i;
503
504         for (i = 0; i < num_qp; ++i) {
505                 if (ibv_destroy_qp(ctx->qp[i])) {
506                         fprintf(stderr, "Couldn't destroy QP[%d]\n", i);
507                         return 1;
508                 }
509         }
510
511         if (ibv_destroy_srq(ctx->srq)) {
512                 fprintf(stderr, "Couldn't destroy SRQ\n");
513                 return 1;
514         }
515
516         if (ibv_destroy_cq(ctx->cq)) {
517                 fprintf(stderr, "Couldn't destroy CQ\n");
518                 return 1;
519         }
520
521         if (ibv_dereg_mr(ctx->mr)) {
522                 fprintf(stderr, "Couldn't deregister MR\n");
523                 return 1;
524         }
525
526         if (ibv_dealloc_pd(ctx->pd)) {
527                 fprintf(stderr, "Couldn't deallocate PD\n");
528                 return 1;
529         }
530
531         if (ctx->channel) {
532                 if (ibv_destroy_comp_channel(ctx->channel)) {
533                         fprintf(stderr, "Couldn't destroy completion channel\n");
534                         return 1;
535                 }
536         }
537
538         if (ibv_close_device(ctx->context)) {
539                 fprintf(stderr, "Couldn't release context\n");
540                 return 1;
541         }
542
543         free(ctx->buf);
544         free(ctx);
545
546         return 0;
547 }
548
549 static int pp_post_recv(struct pingpong_context *ctx, int n)
550 {
551         struct ibv_sge list = {
552                 .addr   = (uintptr_t) ctx->buf,
553                 .length = ctx->size,
554                 .lkey   = ctx->mr->lkey
555         };
556         struct ibv_recv_wr wr = {
557                 .wr_id      = PINGPONG_RECV_WRID,
558                 .sg_list    = &list,
559                 .num_sge    = 1,
560         };
561         struct ibv_recv_wr *bad_wr;
562         int i;
563
564         for (i = 0; i < n; ++i)
565                 if (ibv_post_srq_recv(ctx->srq, &wr, &bad_wr))
566                         break;
567
568         return i;
569 }
570
571 static int pp_post_send(struct pingpong_context *ctx, int qp_index)
572 {
573         struct ibv_sge list = {
574                 .addr   = (uintptr_t) ctx->buf,
575                 .length = ctx->size,
576                 .lkey   = ctx->mr->lkey
577         };
578         struct ibv_send_wr wr = {
579                 .wr_id      = PINGPONG_SEND_WRID,
580                 .sg_list    = &list,
581                 .num_sge    = 1,
582                 .opcode     = IBV_WR_SEND,
583                 .send_flags = ctx->send_flags,
584         };
585         struct ibv_send_wr *bad_wr;
586
587         return ibv_post_send(ctx->qp[qp_index], &wr, &bad_wr);
588 }
589
590 static int find_qp(int qpn, struct pingpong_context *ctx, int num_qp)
591 {
592         int i;
593
594         for (i = 0; i < num_qp; ++i)
595                 if (ctx->qp[i]->qp_num == qpn)
596                         return i;
597
598         return -1;
599 }
600
601 static void usage(const char *argv0)
602 {
603         printf("Usage:\n");
604         printf("  %s            start a server and wait for connection\n", argv0);
605         printf("  %s <host>     connect to server at <host>\n", argv0);
606         printf("\n");
607         printf("Options:\n");
608         printf("  -p, --port=<port>      listen on/connect to port <port> (default 18515)\n");
609         printf("  -d, --ib-dev=<dev>     use IB device <dev> (default first device found)\n");
610         printf("  -i, --ib-port=<port>   use port <port> of IB device (default 1)\n");
611         printf("  -s, --size=<size>      size of message to exchange (default 4096)\n");
612         printf("  -m, --mtu=<size>       path MTU (default 1024)\n");
613         printf("  -q, --num-qp=<num>     number of QPs to use (default 16)\n");
614         printf("  -r, --rx-depth=<dep>   number of receives to post at a time (default 500)\n");
615         printf("  -n, --iters=<iters>    number of exchanges per QP(default 1000)\n");
616         printf("  -l, --sl=<sl>          service level value\n");
617         printf("  -e, --events           sleep on CQ events (default poll)\n");
618         printf("  -g, --gid-idx=<gid index> local port gid index\n");
619 }
620
621 int main(int argc, char *argv[])
622 {
623         struct ibv_device      **dev_list;
624         struct ibv_device       *ib_dev;
625         struct ibv_wc           *wc;
626         struct pingpong_context *ctx;
627         struct pingpong_dest     my_dest[MAX_QP];
628         struct pingpong_dest    *rem_dest;
629         struct timeval           start, end;
630         char                    *ib_devname = NULL;
631         char                    *servername = NULL;
632         unsigned int             port = 18515;
633         int                      ib_port = 1;
634         unsigned int             size = 4096;
635         enum ibv_mtu             mtu = IBV_MTU_1024;
636         unsigned int             num_qp = 16;
637         unsigned int             rx_depth = 500;
638         unsigned int             iters = 1000;
639         int                      use_event = 0;
640         int                      routs;
641         int                      rcnt, scnt;
642         int                      num_wc;
643         int                      i;
644         int                      num_cq_events = 0;
645         int                      sl = 0;
646         int                      gidx = -1;
647         char                     gid[33];
648
649         srand48(getpid() * time(NULL));
650
651         while (1) {
652                 int c;
653
654                 static struct option long_options[] = {
655                         { .name = "port",     .has_arg = 1, .val = 'p' },
656                         { .name = "ib-dev",   .has_arg = 1, .val = 'd' },
657                         { .name = "ib-port",  .has_arg = 1, .val = 'i' },
658                         { .name = "size",     .has_arg = 1, .val = 's' },
659                         { .name = "mtu",      .has_arg = 1, .val = 'm' },
660                         { .name = "num-qp",   .has_arg = 1, .val = 'q' },
661                         { .name = "rx-depth", .has_arg = 1, .val = 'r' },
662                         { .name = "iters",    .has_arg = 1, .val = 'n' },
663                         { .name = "sl",       .has_arg = 1, .val = 'l' },
664                         { .name = "events",   .has_arg = 0, .val = 'e' },
665                         { .name = "gid-idx",  .has_arg = 1, .val = 'g' },
666                         {}
667                 };
668
669                 c = getopt_long(argc, argv, "p:d:i:s:m:q:r:n:l:eg:",
670                                                         long_options, NULL);
671                 if (c == -1)
672                         break;
673
674                 switch (c) {
675                 case 'p':
676                         port = strtoul(optarg, NULL, 0);
677                         if (port > 65535) {
678                                 usage(argv[0]);
679                                 return 1;
680                         }
681                         break;
682
683                 case 'd':
684                         ib_devname = strdupa(optarg);
685                         break;
686
687                 case 'i':
688                         ib_port = strtol(optarg, NULL, 0);
689                         if (ib_port < 1) {
690                                 usage(argv[0]);
691                                 return 1;
692                         }
693                         break;
694
695                 case 's':
696                         size = strtoul(optarg, NULL, 0);
697                         if (size < 1) {
698                                 usage(argv[0]);
699                                 return 1;
700                         }
701                         break;
702
703                 case 'm':
704                         mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0));
705                         if (mtu == 0) {
706                                 usage(argv[0]);
707                                 return 1;
708                         }
709                         break;
710
711                 case 'q':
712                         num_qp = strtoul(optarg, NULL, 0);
713                         break;
714
715                 case 'r':
716                         rx_depth = strtoul(optarg, NULL, 0);
717                         break;
718
719                 case 'n':
720                         iters = strtoul(optarg, NULL, 0);
721                         break;
722
723                 case 'l':
724                         sl = strtol(optarg, NULL, 0);
725                         break;
726
727                 case 'e':
728                         ++use_event;
729                         break;
730
731                 case 'g':
732                         gidx = strtol(optarg, NULL, 0);
733                         break;
734
735                 default:
736                         usage(argv[0]);
737                         return 1;
738                 }
739         }
740
741         if (optind == argc - 1)
742                 servername = strdupa(argv[optind]);
743         else if (optind < argc) {
744                 usage(argv[0]);
745                 return 1;
746         }
747
748         if (num_qp > rx_depth) {
749                 fprintf(stderr, "rx_depth %d is too small for %d QPs -- "
750                         "must have at least one receive per QP.\n",
751                         rx_depth, num_qp);
752                 return 1;
753         }
754
755         num_wc = num_qp + rx_depth;
756         wc     = alloca(num_wc * sizeof *wc);
757
758         page_size = sysconf(_SC_PAGESIZE);
759
760         dev_list = ibv_get_device_list(NULL);
761         if (!dev_list) {
762                 perror("Failed to get IB devices list");
763                 return 1;
764         }
765
766         if (!ib_devname) {
767                 ib_dev = *dev_list;
768                 if (!ib_dev) {
769                         fprintf(stderr, "No IB devices found\n");
770                         return 1;
771                 }
772         } else {
773                 for (i = 0; dev_list[i]; ++i)
774                         if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname))
775                                 break;
776                 ib_dev = dev_list[i];
777                 if (!ib_dev) {
778                         fprintf(stderr, "IB device %s not found\n", ib_devname);
779                         return 1;
780                 }
781         }
782
783         ctx = pp_init_ctx(ib_dev, size, num_qp, rx_depth, ib_port, use_event);
784         if (!ctx)
785                 return 1;
786
787         routs = pp_post_recv(ctx, ctx->rx_depth);
788         if (routs < ctx->rx_depth) {
789                 fprintf(stderr, "Couldn't post receive (%d)\n", routs);
790                 return 1;
791         }
792
793         if (use_event)
794                 if (ibv_req_notify_cq(ctx->cq, 0)) {
795                         fprintf(stderr, "Couldn't request CQ notification\n");
796                         return 1;
797                 }
798
799         memset(my_dest, 0, sizeof my_dest);
800
801         if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) {
802                 fprintf(stderr, "Couldn't get port info\n");
803                 return 1;
804         }
805         for (i = 0; i < num_qp; ++i) {
806                 my_dest[i].qpn = ctx->qp[i]->qp_num;
807                 my_dest[i].psn = lrand48() & 0xffffff;
808                 my_dest[i].lid = ctx->portinfo.lid;
809                 if (ctx->portinfo.link_layer != IBV_LINK_LAYER_ETHERNET
810                                                         && !my_dest[i].lid) {
811                         fprintf(stderr, "Couldn't get local LID\n");
812                         return 1;
813                 }
814
815                 if (gidx >= 0) {
816                         if (ibv_query_gid(ctx->context, ib_port, gidx,
817                                                         &my_dest[i].gid)) {
818                                 fprintf(stderr, "Could not get local gid for "
819                                                         "gid index %d\n", gidx);
820                                 return 1;
821                         }
822                 } else
823                         memset(&my_dest[i].gid, 0, sizeof my_dest[i].gid);
824
825                 inet_ntop(AF_INET6, &my_dest[i].gid, gid, sizeof gid);
826                 printf("  local address:  LID 0x%04x, QPN 0x%06x, PSN 0x%06x, "
827                         "GID %s\n", my_dest[i].lid, my_dest[i].qpn,
828                         my_dest[i].psn, gid);
829         }
830
831         if (servername)
832                 rem_dest = pp_client_exch_dest(servername, port, my_dest);
833         else
834                 rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl,
835                                                                 my_dest, gidx);
836
837         if (!rem_dest)
838                 return 1;
839
840         inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid);
841
842         for (i = 0; i < num_qp; ++i) {
843                 inet_ntop(AF_INET6, &rem_dest[i].gid, gid, sizeof gid);
844                 printf("  remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, "
845                         "GID %s\n", rem_dest[i].lid, rem_dest[i].qpn,
846                         rem_dest[i].psn, gid);
847         }
848
849         if (servername)
850                 if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest,
851                                                                         gidx))
852                         return 1;
853
854         if (servername)
855                 for (i = 0; i < num_qp; ++i) {
856                         if (pp_post_send(ctx, i)) {
857                                 fprintf(stderr, "Couldn't post send\n");
858                                 return 1;
859                         }
860                         ctx->pending[i] = PINGPONG_SEND_WRID | PINGPONG_RECV_WRID;
861                 }
862         else
863                 for (i = 0; i < num_qp; ++i)
864                         ctx->pending[i] = PINGPONG_RECV_WRID;
865
866         if (gettimeofday(&start, NULL)) {
867                 perror("gettimeofday");
868                 return 1;
869         }
870
871         rcnt = scnt = 0;
872         while (rcnt < iters || scnt < iters) {
873                 if (use_event) {
874                         struct ibv_cq *ev_cq;
875                         void          *ev_ctx;
876
877                         if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) {
878                                 fprintf(stderr, "Failed to get cq_event\n");
879                                 return 1;
880                         }
881
882                         ++num_cq_events;
883
884                         if (ev_cq != ctx->cq) {
885                                 fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq);
886                                 return 1;
887                         }
888
889                         if (ibv_req_notify_cq(ctx->cq, 0)) {
890                                 fprintf(stderr, "Couldn't request CQ notification\n");
891                                 return 1;
892                         }
893                 }
894
895                 {
896                         int ne, qp_ind;
897
898                         do {
899                                 ne = ibv_poll_cq(ctx->cq, num_wc, wc);
900                                 if (ne < 0) {
901                                         fprintf(stderr, "poll CQ failed %d\n", ne);
902                                         return 1;
903                                 }
904                         } while (!use_event && ne < 1);
905
906                         for (i = 0; i < ne; ++i) {
907                                 if (wc[i].status != IBV_WC_SUCCESS) {
908                                         fprintf(stderr, "Failed status %s (%d) for wr_id %d\n",
909                                                 ibv_wc_status_str(wc[i].status),
910                                                 wc[i].status, (int) wc[i].wr_id);
911                                         return 1;
912                                 }
913
914                                 qp_ind = find_qp(wc[i].qp_num, ctx, num_qp);
915                                 if (qp_ind < 0) {
916                                         fprintf(stderr, "Couldn't find QPN %06x\n",
917                                                 wc[i].qp_num);
918                                         return 1;
919                                 }
920
921                                 switch ((int) wc[i].wr_id) {
922                                 case PINGPONG_SEND_WRID:
923                                         ++scnt;
924                                         break;
925
926                                 case PINGPONG_RECV_WRID:
927                                         if (--routs <= num_qp) {
928                                                 routs += pp_post_recv(ctx, ctx->rx_depth - routs);
929                                                 if (routs < ctx->rx_depth) {
930                                                         fprintf(stderr,
931                                                                 "Couldn't post receive (%d)\n",
932                                                                 routs);
933                                                         return 1;
934                                                 }
935                                         }
936
937                                         ++rcnt;
938                                         break;
939
940                                 default:
941                                         fprintf(stderr, "Completion for unknown wr_id %d\n",
942                                                 (int) wc[i].wr_id);
943                                         return 1;
944                                 }
945
946                                 ctx->pending[qp_ind] &= ~(int) wc[i].wr_id;
947                                 if (scnt < iters && !ctx->pending[qp_ind]) {
948                                         if (pp_post_send(ctx, qp_ind)) {
949                                                 fprintf(stderr, "Couldn't post send\n");
950                                                 return 1;
951                                         }
952                                         ctx->pending[qp_ind] = PINGPONG_RECV_WRID |
953                                                                PINGPONG_SEND_WRID;
954                                 }
955
956                         }
957                 }
958         }
959
960         if (gettimeofday(&end, NULL)) {
961                 perror("gettimeofday");
962                 return 1;
963         }
964
965         {
966                 float usec = (end.tv_sec - start.tv_sec) * 1000000 +
967                         (end.tv_usec - start.tv_usec);
968                 long long bytes = (long long) size * iters * 2;
969
970                 printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n",
971                        bytes, usec / 1000000., bytes * 8. / usec);
972                 printf("%d iters in %.2f seconds = %.2f usec/iter\n",
973                        iters, usec / 1000000., usec / iters);
974         }
975
976         ibv_ack_cq_events(ctx->cq, num_cq_events);
977
978         if (pp_close_ctx(ctx, num_qp))
979                 return 1;
980
981         ibv_free_device_list(dev_list);
982         free(rem_dest);
983
984         return 0;
985 }