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