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