2 * Copyright (c) 2005-2006,2011-2012 Intel Corporation. All rights reserved.
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:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
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.
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
39 #include <sys/types.h>
40 #include <sys/socket.h>
44 #include <rdma/rdma_cma.h>
49 struct rdma_cm_id *cma_id;
63 struct rdma_event_channel *channel;
64 struct cmatest_node *nodes;
69 struct rdma_addrinfo *rai;
72 static struct cmatest test;
73 static int connections = 1;
74 static int message_size = 100;
75 static int message_count = 10;
76 static const char *port = "7471";
77 static uint8_t set_tos = 0;
79 static uint8_t migrate = 0;
80 static char *dst_addr;
81 static char *src_addr;
82 static struct rdma_addrinfo hints;
84 static int create_message(struct cmatest_node *node)
92 node->mem = malloc(message_size);
94 printf("failed message allocation\n");
97 node->mr = ibv_reg_mr(node->pd, node->mem, message_size,
98 IBV_ACCESS_LOCAL_WRITE);
100 printf("failed to reg MR\n");
109 static int init_node(struct cmatest_node *node)
111 struct ibv_qp_init_attr init_qp_attr;
114 node->pd = ibv_alloc_pd(node->cma_id->verbs);
117 printf("cmatose: unable to allocate PD\n");
121 cqe = message_count ? message_count : 1;
122 node->cq[SEND_CQ_INDEX] = ibv_create_cq(node->cma_id->verbs, cqe, node, NULL, 0);
123 node->cq[RECV_CQ_INDEX] = ibv_create_cq(node->cma_id->verbs, cqe, node, NULL, 0);
124 if (!node->cq[SEND_CQ_INDEX] || !node->cq[RECV_CQ_INDEX]) {
126 printf("cmatose: unable to create CQ\n");
130 memset(&init_qp_attr, 0, sizeof init_qp_attr);
131 init_qp_attr.cap.max_send_wr = cqe;
132 init_qp_attr.cap.max_recv_wr = cqe;
133 init_qp_attr.cap.max_send_sge = 1;
134 init_qp_attr.cap.max_recv_sge = 1;
135 init_qp_attr.qp_context = node;
136 init_qp_attr.sq_sig_all = 1;
137 init_qp_attr.qp_type = IBV_QPT_RC;
138 init_qp_attr.send_cq = node->cq[SEND_CQ_INDEX];
139 init_qp_attr.recv_cq = node->cq[RECV_CQ_INDEX];
140 ret = rdma_create_qp(node->cma_id, node->pd, &init_qp_attr);
142 perror("cmatose: unable to create QP");
146 ret = create_message(node);
148 printf("cmatose: failed to create messages: %d\n", ret);
155 static int post_recvs(struct cmatest_node *node)
157 struct ibv_recv_wr recv_wr, *recv_failure;
165 recv_wr.sg_list = &sge;
167 recv_wr.wr_id = (uintptr_t) node;
169 sge.length = message_size;
170 sge.lkey = node->mr->lkey;
171 sge.addr = (uintptr_t) node->mem;
173 for (i = 0; i < message_count && !ret; i++ ) {
174 ret = ibv_post_recv(node->cma_id->qp, &recv_wr, &recv_failure);
176 printf("failed to post receives: %d\n", ret);
183 static int post_sends(struct cmatest_node *node)
185 struct ibv_send_wr send_wr, *bad_send_wr;
189 if (!node->connected || !message_count)
193 send_wr.sg_list = &sge;
195 send_wr.opcode = IBV_WR_SEND;
196 send_wr.send_flags = 0;
197 send_wr.wr_id = (unsigned long)node;
199 sge.length = message_size;
200 sge.lkey = node->mr->lkey;
201 sge.addr = (uintptr_t) node->mem;
203 for (i = 0; i < message_count && !ret; i++) {
204 ret = ibv_post_send(node->cma_id->qp, &send_wr, &bad_send_wr);
206 printf("failed to post sends: %d\n", ret);
211 static void connect_error(void)
213 test.connects_left--;
216 static int addr_handler(struct cmatest_node *node)
221 ret = rdma_set_option(node->cma_id, RDMA_OPTION_ID,
222 RDMA_OPTION_ID_TOS, &tos, sizeof tos);
224 perror("cmatose: set TOS option failed");
227 ret = rdma_resolve_route(node->cma_id, 2000);
229 perror("cmatose: resolve route failed");
235 static int route_handler(struct cmatest_node *node)
237 struct rdma_conn_param conn_param;
240 ret = init_node(node);
244 ret = post_recvs(node);
248 memset(&conn_param, 0, sizeof conn_param);
249 conn_param.responder_resources = 1;
250 conn_param.initiator_depth = 1;
251 conn_param.retry_count = 5;
252 conn_param.private_data = test.rai->ai_connect;
253 conn_param.private_data_len = test.rai->ai_connect_len;
254 ret = rdma_connect(node->cma_id, &conn_param);
256 perror("cmatose: failure connecting");
265 static int connect_handler(struct rdma_cm_id *cma_id)
267 struct cmatest_node *node;
270 if (test.conn_index == connections) {
274 node = &test.nodes[test.conn_index++];
276 node->cma_id = cma_id;
277 cma_id->context = node;
279 ret = init_node(node);
283 ret = post_recvs(node);
287 ret = rdma_accept(node->cma_id, NULL);
289 perror("cmatose: failure accepting");
298 printf("cmatose: failing connection request\n");
299 rdma_reject(cma_id, NULL, 0);
303 static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
307 switch (event->event) {
308 case RDMA_CM_EVENT_ADDR_RESOLVED:
309 ret = addr_handler(cma_id->context);
311 case RDMA_CM_EVENT_ROUTE_RESOLVED:
312 ret = route_handler(cma_id->context);
314 case RDMA_CM_EVENT_CONNECT_REQUEST:
315 ret = connect_handler(cma_id);
317 case RDMA_CM_EVENT_ESTABLISHED:
318 ((struct cmatest_node *) cma_id->context)->connected = 1;
319 test.connects_left--;
320 test.disconnects_left++;
322 case RDMA_CM_EVENT_ADDR_ERROR:
323 case RDMA_CM_EVENT_ROUTE_ERROR:
324 case RDMA_CM_EVENT_CONNECT_ERROR:
325 case RDMA_CM_EVENT_UNREACHABLE:
326 case RDMA_CM_EVENT_REJECTED:
327 printf("cmatose: event: %s, error: %d\n",
328 rdma_event_str(event->event), event->status);
332 case RDMA_CM_EVENT_DISCONNECTED:
333 rdma_disconnect(cma_id);
334 test.disconnects_left--;
336 case RDMA_CM_EVENT_DEVICE_REMOVAL:
337 /* Cleanup will occur after test completes. */
345 static void destroy_node(struct cmatest_node *node)
350 if (node->cma_id->qp)
351 rdma_destroy_qp(node->cma_id);
353 if (node->cq[SEND_CQ_INDEX])
354 ibv_destroy_cq(node->cq[SEND_CQ_INDEX]);
356 if (node->cq[RECV_CQ_INDEX])
357 ibv_destroy_cq(node->cq[RECV_CQ_INDEX]);
360 ibv_dereg_mr(node->mr);
365 ibv_dealloc_pd(node->pd);
367 /* Destroy the RDMA ID after all device resources */
368 rdma_destroy_id(node->cma_id);
371 static int alloc_nodes(void)
375 test.nodes = malloc(sizeof *test.nodes * connections);
377 printf("cmatose: unable to allocate memory for test nodes\n");
380 memset(test.nodes, 0, sizeof *test.nodes * connections);
382 for (i = 0; i < connections; i++) {
383 test.nodes[i].id = i;
385 ret = rdma_create_id(test.channel,
386 &test.nodes[i].cma_id,
387 &test.nodes[i], hints.ai_port_space);
395 rdma_destroy_id(test.nodes[i].cma_id);
400 static void destroy_nodes(void)
404 for (i = 0; i < connections; i++)
405 destroy_node(&test.nodes[i]);
409 static int poll_cqs(enum CQ_INDEX index)
414 for (i = 0; i < connections; i++) {
415 if (!test.nodes[i].connected)
418 for (done = 0; done < message_count; done += ret) {
419 ret = ibv_poll_cq(test.nodes[i].cq[index], 8, wc);
421 printf("cmatose: failed polling CQ: %d\n", ret);
429 static int connect_events(void)
431 struct rdma_cm_event *event;
434 while (test.connects_left && !ret) {
435 ret = rdma_get_cm_event(test.channel, &event);
437 ret = cma_handler(event->id, event);
438 rdma_ack_cm_event(event);
440 perror("cmatose: failure in rdma_get_cm_event in connect events");
448 static int disconnect_events(void)
450 struct rdma_cm_event *event;
453 while (test.disconnects_left && !ret) {
454 ret = rdma_get_cm_event(test.channel, &event);
456 ret = cma_handler(event->id, event);
457 rdma_ack_cm_event(event);
459 perror("cmatose: failure in rdma_get_cm_event in disconnect events");
467 static int migrate_channel(struct rdma_cm_id *listen_id)
469 struct rdma_event_channel *channel;
472 printf("migrating to new event channel\n");
474 channel = rdma_create_event_channel();
476 perror("cmatose: failed to create event channel");
482 ret = rdma_migrate_id(listen_id, channel);
484 for (i = 0; i < connections && !ret; i++)
485 ret = rdma_migrate_id(test.nodes[i].cma_id, channel);
488 rdma_destroy_event_channel(test.channel);
489 test.channel = channel;
491 perror("cmatose: failure migrating to channel");
496 static int run_server(void)
498 struct rdma_cm_id *listen_id;
501 printf("cmatose: starting server\n");
502 ret = rdma_create_id(test.channel, &listen_id, &test, hints.ai_port_space);
504 perror("cmatose: listen request failed");
508 ret = get_rdma_addr(src_addr, dst_addr, port, &hints, &test.rai);
510 printf("cmatose: getrdmaaddr error: %s\n", gai_strerror(ret));
514 ret = rdma_bind_addr(listen_id, test.rai->ai_src_addr);
516 perror("cmatose: bind address failed");
520 ret = rdma_listen(listen_id, 0);
522 perror("cmatose: failure trying to listen");
526 ret = connect_events();
531 printf("initiating data transfers\n");
532 for (i = 0; i < connections; i++) {
533 ret = post_sends(&test.nodes[i]);
538 printf("completing sends\n");
539 ret = poll_cqs(SEND_CQ_INDEX);
543 printf("receiving data transfers\n");
544 ret = poll_cqs(RECV_CQ_INDEX);
547 printf("data transfers complete\n");
552 ret = migrate_channel(listen_id);
557 printf("cmatose: disconnecting\n");
558 for (i = 0; i < connections; i++) {
559 if (!test.nodes[i].connected)
562 test.nodes[i].connected = 0;
563 rdma_disconnect(test.nodes[i].cma_id);
566 ret = disconnect_events();
568 printf("disconnected\n");
571 rdma_destroy_id(listen_id);
575 static int run_client(void)
579 printf("cmatose: starting client\n");
581 ret = get_rdma_addr(src_addr, dst_addr, port, &hints, &test.rai);
583 printf("cmatose: getaddrinfo error: %s\n", gai_strerror(ret));
587 printf("cmatose: connecting\n");
588 for (i = 0; i < connections; i++) {
589 ret = rdma_resolve_addr(test.nodes[i].cma_id, test.rai->ai_src_addr,
590 test.rai->ai_dst_addr, 2000);
592 perror("cmatose: failure getting addr");
598 ret = connect_events();
603 printf("receiving data transfers\n");
604 ret = poll_cqs(RECV_CQ_INDEX);
608 printf("sending replies\n");
609 for (i = 0; i < connections; i++) {
610 ret = post_sends(&test.nodes[i]);
615 printf("data transfers complete\n");
621 ret = migrate_channel(NULL);
626 ret2 = disconnect_events();
633 int main(int argc, char **argv)
637 hints.ai_port_space = RDMA_PS_TCP;
638 while ((op = getopt(argc, argv, "s:b:f:P:c:C:S:t:p:m")) != -1) {
647 if (!strncasecmp("ip", optarg, 2)) {
648 hints.ai_flags = RAI_NUMERICHOST;
649 } else if (!strncasecmp("gid", optarg, 3)) {
650 hints.ai_flags = RAI_NUMERICHOST | RAI_FAMILY;
651 hints.ai_family = AF_IB;
652 } else if (strncasecmp("name", optarg, 4)) {
653 fprintf(stderr, "Warning: unknown address format\n");
657 if (!strncasecmp("ib", optarg, 2)) {
658 hints.ai_port_space = RDMA_PS_IB;
659 } else if (strncasecmp("tcp", optarg, 3)) {
660 fprintf(stderr, "Warning: unknown port space format\n");
664 connections = atoi(optarg);
667 message_count = atoi(optarg);
670 message_size = atoi(optarg);
674 tos = (uint8_t) strtoul(optarg, NULL, 0);
683 printf("usage: %s\n", argv[0]);
684 printf("\t[-s server_address]\n");
685 printf("\t[-b bind_address]\n");
686 printf("\t[-f address_format]\n");
687 printf("\t name, ip, ipv6, or gid\n");
688 printf("\t[-P port_space]\n");
689 printf("\t tcp or ib\n");
690 printf("\t[-c connections]\n");
691 printf("\t[-C message_count]\n");
692 printf("\t[-S message_size]\n");
693 printf("\t[-t type_of_service]\n");
694 printf("\t[-p port_number]\n");
695 printf("\t[-m(igrate)]\n");
700 test.connects_left = connections;
702 test.channel = rdma_create_event_channel();
704 printf("failed to create event channel\n");
714 hints.ai_flags |= RAI_PASSIVE;
718 printf("test complete\n");
720 rdma_destroy_event_channel(test.channel);
722 rdma_freeaddrinfo(test.rai);
724 printf("return status %d\n", ret);