librdmacm: provide OFED compatibility library.
[mirror/winof/.git] / ulp / librdmacm / examples / udaddy / udaddy.c
1 /*\r
2  * Copyright (c) 2005-2006 Intel Corporation.  All rights reserved.\r
3  *\r
4  * This software is available to you under a choice of one of two\r
5  * licenses.  You may choose to be licensed under the terms of the GNU\r
6  * General Public License (GPL) Version 2, available from the file\r
7  * COPYING in the main directory of this source tree, or the\r
8  * OpenIB.org BSD license below:\r
9  *\r
10  *     Redistribution and use in source and binary forms, with or\r
11  *     without modification, are permitted provided that the following\r
12  *     conditions are met:\r
13  *\r
14  *      - Redistributions of source code must retain the above\r
15  *        copyright notice, this list of conditions and the following\r
16  *        disclaimer.\r
17  *\r
18  *      - Redistributions in binary form must reproduce the above\r
19  *        copyright notice, this list of conditions and the following\r
20  *        disclaimer in the documentation and/or other materials\r
21  *        provided with the distribution.\r
22  *\r
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
30  * SOFTWARE.\r
31  *\r
32  * $Id$\r
33  */\r
34 \r
35 #include <stdlib.h>\r
36 #include <string.h>\r
37 #include <stdio.h>\r
38 #include <errno.h>\r
39 #include <sys/types.h>\r
40 #include <netinet/in.h>\r
41 #include <sys/socket.h>\r
42 #include <netdb.h>\r
43 #include <byteswap.h>\r
44 #include <getopt.h>\r
45 \r
46 #include <rdma/rdma_cma.h>\r
47 \r
48 struct cmatest_node {\r
49         int                     id;\r
50         struct rdma_cm_id       *cma_id;\r
51         int                     connected;\r
52         struct ibv_pd           *pd;\r
53         struct ibv_cq           *cq;\r
54         struct ibv_mr           *mr;\r
55         struct ibv_ah           *ah;\r
56         uint32_t                remote_qpn;\r
57         uint32_t                remote_qkey;\r
58         void                    *mem;\r
59 };\r
60 \r
61 struct cmatest {\r
62         struct rdma_event_channel *channel;\r
63         struct cmatest_node     *nodes;\r
64         int                     conn_index;\r
65         int                     connects_left;\r
66 \r
67         struct sockaddr_in      dst_in;\r
68         struct sockaddr         *dst_addr;\r
69         struct sockaddr_in      src_in;\r
70         struct sockaddr         *src_addr;\r
71 };\r
72 \r
73 static struct cmatest test;\r
74 static int connections = 1;\r
75 static int message_size = 100;\r
76 static int message_count = 10;\r
77 static uint16_t port = 7174;\r
78 static uint8_t set_tos = 0;\r
79 static uint8_t tos;\r
80 static char *dst_addr;\r
81 static char *src_addr;\r
82 static enum rdma_port_space port_space = RDMA_PS_UDP;\r
83 \r
84 static int create_message(struct cmatest_node *node)\r
85 {\r
86         if (!message_size)\r
87                 message_count = 0;\r
88 \r
89         if (!message_count)\r
90                 return 0;\r
91 \r
92         node->mem = malloc(message_size + sizeof(struct ibv_grh));\r
93         if (!node->mem) {\r
94                 printf("failed message allocation\n");\r
95                 return -1;\r
96         }\r
97         node->mr = ibv_reg_mr(node->pd, node->mem,\r
98                               message_size + sizeof(struct ibv_grh),\r
99                               IBV_ACCESS_LOCAL_WRITE);\r
100         if (!node->mr) {\r
101                 printf("failed to reg MR\n");\r
102                 goto err;\r
103         }\r
104         return 0;\r
105 err:\r
106         free(node->mem);\r
107         return -1;\r
108 }\r
109 \r
110 static int verify_test_params(struct cmatest_node *node)\r
111 {\r
112         struct ibv_port_attr port_attr;\r
113         int ret;\r
114 \r
115         ret = ibv_query_port(node->cma_id->verbs, node->cma_id->port_num,\r
116                              &port_attr);\r
117         if (ret)\r
118                 return ret;\r
119 \r
120         if (message_count && message_size > (1 << (port_attr.active_mtu + 7))) {\r
121                 printf("udaddy: message_size %d is larger than active mtu %d\n",\r
122                        message_size, 1 << (port_attr.active_mtu + 7));\r
123                 return -EINVAL;\r
124         }\r
125 \r
126         return 0;\r
127 }\r
128 \r
129 static int init_node(struct cmatest_node *node)\r
130 {\r
131         struct ibv_qp_init_attr init_qp_attr;\r
132         int cqe, ret;\r
133 \r
134         node->pd = ibv_alloc_pd(node->cma_id->verbs);\r
135         if (!node->pd) {\r
136                 ret = -ENOMEM;\r
137                 printf("udaddy: unable to allocate PD\n");\r
138                 goto out;\r
139         }\r
140 \r
141         cqe = message_count ? message_count * 2 : 2;\r
142         node->cq = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0);\r
143         if (!node->cq) {\r
144                 ret = -ENOMEM;\r
145                 printf("udaddy: unable to create CQ\n");\r
146                 goto out;\r
147         }\r
148 \r
149         memset(&init_qp_attr, 0, sizeof init_qp_attr);\r
150         init_qp_attr.cap.max_send_wr = message_count ? message_count : 1;\r
151         init_qp_attr.cap.max_recv_wr = message_count ? message_count : 1;\r
152         init_qp_attr.cap.max_send_sge = 1;\r
153         init_qp_attr.cap.max_recv_sge = 1;\r
154         init_qp_attr.qp_context = node;\r
155         init_qp_attr.sq_sig_all = 0;\r
156         init_qp_attr.qp_type = IBV_QPT_UD;\r
157         init_qp_attr.send_cq = node->cq;\r
158         init_qp_attr.recv_cq = node->cq;\r
159         ret = rdma_create_qp(node->cma_id, node->pd, &init_qp_attr);\r
160         if (ret) {\r
161                 printf("udaddy: unable to create QP: %d\n", ret);\r
162                 goto out;\r
163         }\r
164 \r
165         ret = create_message(node);\r
166         if (ret) {\r
167                 printf("udaddy: failed to create messages: %d\n", ret);\r
168                 goto out;\r
169         }\r
170 out:\r
171         return ret;\r
172 }\r
173 \r
174 static int post_recvs(struct cmatest_node *node)\r
175 {\r
176         struct ibv_recv_wr recv_wr, *recv_failure;\r
177         struct ibv_sge sge;\r
178         int i, ret = 0;\r
179 \r
180         if (!message_count)\r
181                 return 0;\r
182 \r
183         recv_wr.next = NULL;\r
184         recv_wr.sg_list = &sge;\r
185         recv_wr.num_sge = 1;\r
186         recv_wr.wr_id = (uintptr_t) node;\r
187 \r
188         sge.length = message_size + sizeof(struct ibv_grh);\r
189         sge.lkey = node->mr->lkey;\r
190         sge.addr = (uintptr_t) node->mem;\r
191 \r
192         for (i = 0; i < message_count && !ret; i++ ) {\r
193                 ret = ibv_post_recv(node->cma_id->qp, &recv_wr, &recv_failure);\r
194                 if (ret) {\r
195                         printf("failed to post receives: %d\n", ret);\r
196                         break;\r
197                 }\r
198         }\r
199         return ret;\r
200 }\r
201 \r
202 static int post_sends(struct cmatest_node *node, int signal_flag)\r
203 {\r
204         struct ibv_send_wr send_wr, *bad_send_wr;\r
205         struct ibv_sge sge;\r
206         int i, ret = 0;\r
207 \r
208         if (!node->connected || !message_count)\r
209                 return 0;\r
210 \r
211         send_wr.next = NULL;\r
212         send_wr.sg_list = &sge;\r
213         send_wr.num_sge = 1;\r
214         send_wr.opcode = IBV_WR_SEND_WITH_IMM;\r
215         send_wr.send_flags = signal_flag;\r
216         send_wr.wr_id = (unsigned long)node;\r
217         send_wr.imm_data = htonl(node->cma_id->qp->qp_num);\r
218 \r
219         send_wr.wr.ud.ah = node->ah;\r
220         send_wr.wr.ud.remote_qpn = node->remote_qpn;\r
221         send_wr.wr.ud.remote_qkey = node->remote_qkey;\r
222 \r
223         sge.length = message_size;\r
224         sge.lkey = node->mr->lkey;\r
225         sge.addr = (uintptr_t) node->mem;\r
226 \r
227         for (i = 0; i < message_count && !ret; i++) {\r
228                 ret = ibv_post_send(node->cma_id->qp, &send_wr, &bad_send_wr);\r
229                 if (ret) \r
230                         printf("failed to post sends: %d\n", ret);\r
231         }\r
232         return ret;\r
233 }\r
234 \r
235 static void connect_error(void)\r
236 {\r
237         test.connects_left--;\r
238 }\r
239 \r
240 static int addr_handler(struct cmatest_node *node)\r
241 {\r
242         int ret;\r
243 \r
244         if (set_tos) {\r
245                 ret = rdma_set_option(node->cma_id, RDMA_OPTION_ID,\r
246                                       RDMA_OPTION_ID_TOS, &tos, sizeof tos);\r
247                 if (ret)\r
248                         printf("udaddy: set TOS option failed: %d\n", ret);\r
249         }\r
250 \r
251         ret = rdma_resolve_route(node->cma_id, 2000);\r
252         if (ret) {\r
253                 printf("udaddy: resolve route failed: %d\n", ret);\r
254                 connect_error();\r
255         }\r
256         return ret;\r
257 }\r
258 \r
259 static int route_handler(struct cmatest_node *node)\r
260 {\r
261         struct rdma_conn_param conn_param;\r
262         int ret;\r
263 \r
264         ret = verify_test_params(node);\r
265         if (ret)\r
266                 goto err;\r
267 \r
268         ret = init_node(node);\r
269         if (ret)\r
270                 goto err;\r
271 \r
272         ret = post_recvs(node);\r
273         if (ret)\r
274                 goto err;\r
275 \r
276         memset(&conn_param, 0, sizeof conn_param);\r
277         ret = rdma_connect(node->cma_id, &conn_param);\r
278         if (ret) {\r
279                 printf("udaddy: failure connecting: %d\n", ret);\r
280                 goto err;\r
281         }\r
282         return 0;\r
283 err:\r
284         connect_error();\r
285         return ret;\r
286 }\r
287 \r
288 static int connect_handler(struct rdma_cm_id *cma_id)\r
289 {\r
290         struct cmatest_node *node;\r
291         struct rdma_conn_param conn_param;\r
292         int ret;\r
293 \r
294         if (test.conn_index == connections) {\r
295                 ret = -ENOMEM;\r
296                 goto err1;\r
297         }\r
298         node = &test.nodes[test.conn_index++];\r
299 \r
300         node->cma_id = cma_id;\r
301         cma_id->context = node;\r
302 \r
303         ret = verify_test_params(node);\r
304         if (ret)\r
305                 goto err2;\r
306 \r
307         ret = init_node(node);\r
308         if (ret)\r
309                 goto err2;\r
310 \r
311         ret = post_recvs(node);\r
312         if (ret)\r
313                 goto err2;\r
314 \r
315         memset(&conn_param, 0, sizeof conn_param);\r
316         conn_param.qp_num = node->cma_id->qp->qp_num;\r
317         ret = rdma_accept(node->cma_id, &conn_param);\r
318         if (ret) {\r
319                 printf("udaddy: failure accepting: %d\n", ret);\r
320                 goto err2;\r
321         }\r
322         node->connected = 1;\r
323         test.connects_left--;\r
324         return 0;\r
325 \r
326 err2:\r
327         node->cma_id = NULL;\r
328         connect_error();\r
329 err1:\r
330         printf("udaddy: failing connection request\n");\r
331         rdma_reject(cma_id, NULL, 0);\r
332         return ret;\r
333 }\r
334 \r
335 static int resolved_handler(struct cmatest_node *node,\r
336                             struct rdma_cm_event *event)\r
337 {\r
338         node->remote_qpn = event->param.ud.qp_num;\r
339         node->remote_qkey = event->param.ud.qkey;\r
340         node->ah = ibv_create_ah(node->pd, &event->param.ud.ah_attr);\r
341         if (!node->ah) {\r
342                 printf("udaddy: failure creating address handle\n");\r
343                 goto err;\r
344         }\r
345 \r
346         node->connected = 1;\r
347         test.connects_left--;\r
348         return 0;\r
349 err:\r
350         connect_error();\r
351         return -1;\r
352 }\r
353 \r
354 static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)\r
355 {\r
356         int ret = 0;\r
357 \r
358         switch (event->event) {\r
359         case RDMA_CM_EVENT_ADDR_RESOLVED:\r
360                 ret = addr_handler(cma_id->context);\r
361                 break;\r
362         case RDMA_CM_EVENT_ROUTE_RESOLVED:\r
363                 ret = route_handler(cma_id->context);\r
364                 break;\r
365         case RDMA_CM_EVENT_CONNECT_REQUEST:\r
366                 ret = connect_handler(cma_id);\r
367                 break;\r
368         case RDMA_CM_EVENT_ESTABLISHED:\r
369                 ret = resolved_handler(cma_id->context, event);\r
370                 break;\r
371         case RDMA_CM_EVENT_ADDR_ERROR:\r
372         case RDMA_CM_EVENT_ROUTE_ERROR:\r
373         case RDMA_CM_EVENT_CONNECT_ERROR:\r
374         case RDMA_CM_EVENT_UNREACHABLE:\r
375         case RDMA_CM_EVENT_REJECTED:\r
376                 printf("udaddy: event: %s, error: %d\n",\r
377                        rdma_event_str(event->event), event->status);\r
378                 connect_error();\r
379                 ret = event->status;\r
380                 break;\r
381         case RDMA_CM_EVENT_DEVICE_REMOVAL:\r
382                 /* Cleanup will occur after test completes. */\r
383                 break;\r
384         default:\r
385                 break;\r
386         }\r
387         return ret;\r
388 }\r
389 \r
390 static void destroy_node(struct cmatest_node *node)\r
391 {\r
392         if (!node->cma_id)\r
393                 return;\r
394 \r
395         if (node->ah)\r
396                 ibv_destroy_ah(node->ah);\r
397 \r
398         if (node->cma_id->qp)\r
399                 rdma_destroy_qp(node->cma_id);\r
400 \r
401         if (node->cq)\r
402                 ibv_destroy_cq(node->cq);\r
403 \r
404         if (node->mem) {\r
405                 ibv_dereg_mr(node->mr);\r
406                 free(node->mem);\r
407         }\r
408 \r
409         if (node->pd)\r
410                 ibv_dealloc_pd(node->pd);\r
411 \r
412         /* Destroy the RDMA ID after all device resources */\r
413         rdma_destroy_id(node->cma_id);\r
414 }\r
415 \r
416 static int alloc_nodes(void)\r
417 {\r
418         int ret, i;\r
419 \r
420         test.nodes = malloc(sizeof *test.nodes * connections);\r
421         if (!test.nodes) {\r
422                 printf("udaddy: unable to allocate memory for test nodes\n");\r
423                 return -ENOMEM;\r
424         }\r
425         memset(test.nodes, 0, sizeof *test.nodes * connections);\r
426 \r
427         for (i = 0; i < connections; i++) {\r
428                 test.nodes[i].id = i;\r
429                 if (dst_addr) {\r
430                         ret = rdma_create_id(test.channel,\r
431                                              &test.nodes[i].cma_id,\r
432                                              &test.nodes[i], port_space);\r
433                         if (ret)\r
434                                 goto err;\r
435                 }\r
436         }\r
437         return 0;\r
438 err:\r
439         while (--i >= 0)\r
440                 rdma_destroy_id(test.nodes[i].cma_id);\r
441         free(test.nodes);\r
442         return ret;\r
443 }\r
444 \r
445 static void destroy_nodes(void)\r
446 {\r
447         int i;\r
448 \r
449         for (i = 0; i < connections; i++)\r
450                 destroy_node(&test.nodes[i]);\r
451         free(test.nodes);\r
452 }\r
453 \r
454 static void create_reply_ah(struct cmatest_node *node, struct ibv_wc *wc)\r
455 {\r
456         struct ibv_qp_attr attr;\r
457         struct ibv_qp_init_attr init_attr;\r
458 \r
459         node->ah = ibv_create_ah_from_wc(node->pd, wc, node->mem,\r
460                                          node->cma_id->port_num);\r
461         node->remote_qpn = ntohl(wc->imm_data);\r
462 \r
463         ibv_query_qp(node->cma_id->qp, &attr, IBV_QP_QKEY, &init_attr);\r
464         node->remote_qkey = attr.qkey;\r
465 }\r
466 \r
467 static int poll_cqs(void)\r
468 {\r
469         struct ibv_wc wc[8];\r
470         int done, i, ret;\r
471 \r
472         for (i = 0; i < connections; i++) {\r
473                 if (!test.nodes[i].connected)\r
474                         continue;\r
475 \r
476                 for (done = 0; done < message_count; done += ret) {\r
477                         ret = ibv_poll_cq(test.nodes[i].cq, 8, wc);\r
478                         if (ret < 0) {\r
479                                 printf("udaddy: failed polling CQ: %d\n", ret);\r
480                                 return ret;\r
481                         }\r
482 \r
483                         if (ret && !test.nodes[i].ah)\r
484                                 create_reply_ah(&test.nodes[i], wc);\r
485                 }\r
486         }\r
487         return 0;\r
488 }\r
489 \r
490 static int connect_events(void)\r
491 {\r
492         struct rdma_cm_event *event;\r
493         int ret = 0;\r
494 \r
495         while (test.connects_left && !ret) {\r
496                 ret = rdma_get_cm_event(test.channel, &event);\r
497                 if (!ret) {\r
498                         ret = cma_handler(event->id, event);\r
499                         rdma_ack_cm_event(event);\r
500                 }\r
501         }\r
502         return ret;\r
503 }\r
504 \r
505 static int get_addr(char *dst, struct sockaddr_in *addr)\r
506 {\r
507         struct addrinfo *res;\r
508         int ret;\r
509 \r
510         ret = getaddrinfo(dst, NULL, NULL, &res);\r
511         if (ret) {\r
512                 printf("getaddrinfo failed - invalid hostname or IP address\n");\r
513                 return ret;\r
514         }\r
515 \r
516         if (res->ai_family != PF_INET) {\r
517                 ret = -1;\r
518                 goto out;\r
519         }\r
520 \r
521         *addr = *(struct sockaddr_in *) res->ai_addr;\r
522 out:\r
523         freeaddrinfo(res);\r
524         return ret;\r
525 }\r
526 \r
527 static int run_server(void)\r
528 {\r
529         struct rdma_cm_id *listen_id;\r
530         int i, ret;\r
531 \r
532         printf("udaddy: starting server\n");\r
533         ret = rdma_create_id(test.channel, &listen_id, &test, port_space);\r
534         if (ret) {\r
535                 printf("udaddy: listen request failed\n");\r
536                 return ret;\r
537         }\r
538 \r
539         if (src_addr) {\r
540                 ret = get_addr(src_addr, &test.src_in);\r
541                 if (ret)\r
542                         goto out;\r
543         } else\r
544                 test.src_in.sin_family = PF_INET;\r
545 \r
546         test.src_in.sin_port = port;\r
547         ret = rdma_bind_addr(listen_id, test.src_addr);\r
548         if (ret) {\r
549                 printf("udaddy: bind address failed: %d\n", ret);\r
550                 return ret;\r
551         }\r
552 \r
553         ret = rdma_listen(listen_id, 0);\r
554         if (ret) {\r
555                 printf("udaddy: failure trying to listen: %d\n", ret);\r
556                 goto out;\r
557         }\r
558 \r
559         connect_events();\r
560 \r
561         if (message_count) {\r
562                 printf("receiving data transfers\n");\r
563                 ret = poll_cqs();\r
564                 if (ret)\r
565                         goto out;\r
566 \r
567                 printf("sending replies\n");\r
568                 for (i = 0; i < connections; i++) {\r
569                         ret = post_sends(&test.nodes[i], IBV_SEND_SIGNALED);\r
570                         if (ret)\r
571                                 goto out;\r
572                 }\r
573 \r
574                 ret = poll_cqs();\r
575                 if (ret)\r
576                         goto out;\r
577                 printf("data transfers complete\n");\r
578         }\r
579 out:\r
580         rdma_destroy_id(listen_id);\r
581         return ret;\r
582 }\r
583 \r
584 static int run_client(void)\r
585 {\r
586         int i, ret;\r
587 \r
588         printf("udaddy: starting client\n");\r
589         if (src_addr) {\r
590                 ret = get_addr(src_addr, &test.src_in);\r
591                 if (ret)\r
592                         return ret;\r
593         }\r
594 \r
595         ret = get_addr(dst_addr, &test.dst_in);\r
596         if (ret)\r
597                 return ret;\r
598 \r
599         test.dst_in.sin_port = port;\r
600 \r
601         printf("udaddy: connecting\n");\r
602         for (i = 0; i < connections; i++) {\r
603                 ret = rdma_resolve_addr(test.nodes[i].cma_id,\r
604                                         src_addr ? test.src_addr : NULL,\r
605                                         test.dst_addr, 2000);\r
606                 if (ret) {\r
607                         printf("udaddy: failure getting addr: %d\n", ret);\r
608                         connect_error();\r
609                         return ret;\r
610                 }\r
611         }\r
612 \r
613         ret = connect_events();\r
614         if (ret)\r
615                 goto out;\r
616 \r
617         if (message_count) {\r
618                 printf("initiating data transfers\n");\r
619                 for (i = 0; i < connections; i++) {\r
620                         ret = post_sends(&test.nodes[i], 0);\r
621                         if (ret)\r
622                                 goto out;\r
623                 }\r
624                 printf("receiving data transfers\n");\r
625                 ret = poll_cqs();\r
626                 if (ret)\r
627                         goto out;\r
628 \r
629                 printf("data transfers complete\n");\r
630         }\r
631 out:\r
632         return ret;\r
633 }\r
634 \r
635 int main(int argc, char **argv)\r
636 {\r
637         int op, ret;\r
638 \r
639         while ((op = getopt(argc, argv, "s:b:c:C:S:t:p:")) != -1) {\r
640                 switch (op) {\r
641                 case 's':\r
642                         dst_addr = optarg;\r
643                         break;\r
644                 case 'b':\r
645                         src_addr = optarg;\r
646                         break;\r
647                 case 'c':\r
648                         connections = atoi(optarg);\r
649                         break;\r
650                 case 'C':\r
651                         message_count = atoi(optarg);\r
652                         break;\r
653                 case 'S':\r
654                         message_size = atoi(optarg);\r
655                         break;\r
656                 case 't':\r
657                         set_tos = 1;\r
658                         tos = (uint8_t) atoi(optarg);\r
659                         break;\r
660                 case 'p':\r
661                         port_space = strtol(optarg, NULL, 0);\r
662                         break;\r
663                 default:\r
664                         printf("usage: %s\n", argv[0]);\r
665                         printf("\t[-s server_address]\n");\r
666                         printf("\t[-b bind_address]\n");\r
667                         printf("\t[-c connections]\n");\r
668                         printf("\t[-C message_count]\n");\r
669                         printf("\t[-S message_size]\n");\r
670                         printf("\t[-t type_of_service]\n");\r
671                         printf("\t[-p port_space - %#x for UDP (default), "\r
672                                "%#x for IPOIB]\n", RDMA_PS_UDP, RDMA_PS_IPOIB);\r
673                         exit(1);\r
674                 }\r
675         }\r
676 \r
677         test.dst_addr = (struct sockaddr *) &test.dst_in;\r
678         test.src_addr = (struct sockaddr *) &test.src_in;\r
679         test.connects_left = connections;\r
680 \r
681         test.channel = rdma_create_event_channel();\r
682         if (!test.channel) {\r
683                 printf("failed to create event channel\n");\r
684                 exit(1);\r
685         }\r
686 \r
687         if (alloc_nodes())\r
688                 exit(1);\r
689 \r
690         if (dst_addr)\r
691                 ret = run_client();\r
692         else\r
693                 ret = run_server();\r
694 \r
695         printf("test complete\n");\r
696         destroy_nodes();\r
697         rdma_destroy_event_channel(test.channel);\r
698 \r
699         printf("return status %d\n", ret);\r
700         return ret;\r
701 }\r