2 * Copyright (c) 2005-2009 Intel Corporation. All rights reserved.
\r
4 * This software is available to you under the OpenIB.org BSD license
\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
11 * - Redistributions of source code must retain the above
\r
12 * copyright notice, this list of conditions and the following
\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
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
33 #include <ws2tcpip.h>
\r
34 #include <winsock2.h>
\r
37 #include "..\..\..\..\etc\user\getopt.c"
\r
38 #include <rdma/rdma_cma.h>
\r
40 struct cmatest_node {
\r
42 struct rdma_cm_id *cma_id;
\r
45 struct ibv_cq *cq[2];
\r
56 struct rdma_event_channel *channel;
\r
57 struct cmatest_node *nodes;
\r
60 int disconnects_left;
\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
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
75 static uint8_t migrate = 0;
\r
76 static char *dst_addr;
\r
77 static char *src_addr;
\r
79 static int create_message(struct cmatest_node *node)
\r
87 node->mem = malloc(message_size);
\r
89 printf("failed message allocation\n");
\r
92 node->mr = ibv_reg_mr(node->pd, node->mem, message_size,
\r
93 IBV_ACCESS_LOCAL_WRITE);
\r
95 printf("failed to reg MR\n");
\r
104 static int init_node(struct cmatest_node *node)
\r
106 struct ibv_qp_init_attr init_qp_attr;
\r
109 node->pd = ibv_alloc_pd(node->cma_id->verbs);
\r
112 printf("cmatose: unable to allocate PD\n");
\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
121 printf("cmatose: unable to create CQs\n");
\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
137 printf("cmatose: unable to create QP: 0x%x\n", ret);
\r
141 ret = create_message(node);
\r
143 printf("cmatose: failed to create messages: 0x%x\n", ret);
\r
150 static int post_recvs(struct cmatest_node *node)
\r
152 struct ibv_recv_wr recv_wr, *recv_failure;
\r
153 struct ibv_sge sge;
\r
156 if (!message_count)
\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
164 sge.length = message_size;
\r
165 sge.lkey = node->mr->lkey;
\r
166 sge.addr = (uintptr_t) node->mem;
\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
171 printf("failed to post receives: 0x%x\n", ret);
\r
178 static int post_sends(struct cmatest_node *node)
\r
180 struct ibv_send_wr send_wr, *bad_send_wr;
\r
181 struct ibv_sge sge;
\r
184 if (!node->connected || !message_count)
\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
194 sge.length = message_size;
\r
195 sge.lkey = node->mr->lkey;
\r
196 sge.addr = (uintptr_t) node->mem;
\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
201 printf("failed to post sends: 0x%x\n", ret);
\r
206 static void connect_error(void)
\r
208 test.disconnects_left--;
\r
209 test.connects_left--;
\r
212 static int addr_handler(struct cmatest_node *node)
\r
217 ret = rdma_set_option(node->cma_id, RDMA_OPTION_ID,
\r
218 RDMA_OPTION_ID_TOS, &tos, sizeof tos);
\r
220 printf("cmatose: set TOS option failed: 0x%x\n", ret);
\r
223 ret = rdma_resolve_route(node->cma_id, 2000);
\r
225 printf("cmatose: resolve route failed: 0x%x\n", ret);
\r
231 static int route_handler(struct cmatest_node *node)
\r
233 struct rdma_conn_param conn_param;
\r
236 ret = init_node(node);
\r
240 ret = post_recvs(node);
\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
250 printf("cmatose: failure connecting: 0x%x\n", ret);
\r
259 static int connect_handler(struct rdma_cm_id *cma_id)
\r
261 struct cmatest_node *node;
\r
262 struct rdma_conn_param conn_param;
\r
265 if (test.conn_index == connections) {
\r
269 node = &test.nodes[test.conn_index++];
\r
271 node->cma_id = cma_id;
\r
272 cma_id->context = node;
\r
274 ret = init_node(node);
\r
278 ret = post_recvs(node);
\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
287 printf("cmatose: failure accepting: 0x%x\n", ret);
\r
293 node->cma_id = NULL;
\r
296 printf("cmatose: failing connection request\n");
\r
297 rdma_reject(cma_id, NULL, 0);
\r
301 static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
\r
305 switch (event->event) {
\r
306 case RDMA_CM_EVENT_ADDR_RESOLVED:
\r
307 ret = addr_handler(cma_id->context);
\r
309 case RDMA_CM_EVENT_ROUTE_RESOLVED:
\r
310 ret = route_handler(cma_id->context);
\r
312 case RDMA_CM_EVENT_CONNECT_REQUEST:
\r
313 ret = connect_handler(cma_id);
\r
315 case RDMA_CM_EVENT_ESTABLISHED:
\r
316 ((struct cmatest_node *) cma_id->context)->connected = 1;
\r
317 test.connects_left--;
\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
328 case RDMA_CM_EVENT_DISCONNECTED:
\r
329 rdma_disconnect(cma_id);
\r
330 test.disconnects_left--;
\r
332 case RDMA_CM_EVENT_DEVICE_REMOVAL:
\r
333 /* Cleanup will occur after test completes. */
\r
341 static void destroy_node(struct cmatest_node *node)
\r
346 if (node->cma_id->qp)
\r
347 rdma_destroy_qp(node->cma_id);
\r
349 if (node->cq[SEND_CQ_INDEX])
\r
350 ibv_destroy_cq(node->cq[SEND_CQ_INDEX]);
\r
352 if (node->cq[RECV_CQ_INDEX])
\r
353 ibv_destroy_cq(node->cq[RECV_CQ_INDEX]);
\r
356 ibv_dereg_mr(node->mr);
\r
361 ibv_dealloc_pd(node->pd);
\r
363 /* Destroy the RDMA ID after all device resources */
\r
364 rdma_destroy_id(node->cma_id);
\r
367 static int alloc_nodes(void)
\r
371 test.nodes = malloc(sizeof *test.nodes * connections);
\r
373 printf("cmatose: unable to allocate memory for test nodes\n");
\r
376 memset(test.nodes, 0, sizeof *test.nodes * connections);
\r
378 for (i = 0; i < connections; i++) {
\r
379 test.nodes[i].id = i;
\r
381 ret = rdma_create_id(test.channel,
\r
382 &test.nodes[i].cma_id,
\r
383 &test.nodes[i], RDMA_PS_TCP);
\r
391 rdma_destroy_id(test.nodes[i].cma_id);
\r
396 static void destroy_nodes(void)
\r
400 for (i = 0; i < connections; i++)
\r
401 destroy_node(&test.nodes[i]);
\r
405 static int poll_cqs(enum CQ_INDEX index)
\r
407 struct ibv_wc wc[8];
\r
410 for (i = 0; i < connections; i++) {
\r
411 if (!test.nodes[i].connected)
\r
414 for (done = 0; done < message_count; done += ret) {
\r
415 ret = ibv_poll_cq(test.nodes[i].cq[index], 8, wc);
\r
417 printf("cmatose: failed polling CQ: 0x%x\n", ret);
\r
425 static int connect_events(void)
\r
427 struct rdma_cm_event *event;
\r
428 int err = 0, ret = 0;
\r
430 while (test.connects_left && !err) {
\r
431 err = rdma_get_cm_event(test.channel, &event);
\r
433 cma_handler(event->id, event);
\r
434 rdma_ack_cm_event(event);
\r
436 printf("cmatose: failure in rdma_get_cm_event in connect events\n");
\r
444 static int disconnect_events(void)
\r
446 struct rdma_cm_event *event;
\r
447 int err = 0, ret = 0;
\r
449 while (test.disconnects_left && !err) {
\r
450 err = rdma_get_cm_event(test.channel, &event);
\r
452 cma_handler(event->id, event);
\r
453 rdma_ack_cm_event(event);
\r
455 printf("cmatose: failure in rdma_get_cm_event in disconnect events\n");
\r
463 static int migrate_channel(struct rdma_cm_id *listen_id)
\r
465 struct rdma_event_channel *channel;
\r
468 printf("migrating to new event channel\n");
\r
470 channel = rdma_create_event_channel();
\r
472 printf("cmatose: failed to create event channel\n");
\r
478 ret = rdma_migrate_id(listen_id, channel);
\r
480 for (i = 0; i < connections && !ret; i++)
\r
481 ret = rdma_migrate_id(test.nodes[i].cma_id, channel);
\r
484 rdma_destroy_event_channel(test.channel);
\r
485 test.channel = channel;
\r
487 printf("cmatose: failure migrating to channel: 0x%x\n", ret);
\r
492 static int get_addr(char *dst, struct sockaddr_in *addr)
\r
494 struct addrinfo *res;
\r
497 ret = getaddrinfo(dst, NULL, NULL, &res);
\r
499 printf("getaddrinfo failed - invalid hostname or IP address\n");
\r
503 if (res->ai_family != PF_INET) {
\r
508 *addr = *(struct sockaddr_in *) res->ai_addr;
\r
514 static int run_server(void)
\r
516 struct rdma_cm_id *listen_id;
\r
519 printf("cmatose: starting server\n");
\r
520 ret = rdma_create_id(test.channel, &listen_id, &test, RDMA_PS_TCP);
\r
522 printf("cmatose: listen request failed\n");
\r
527 ret = get_addr(src_addr, &test.src_in);
\r
531 test.src_in.sin_family = PF_INET;
\r
533 test.src_in.sin_port = port;
\r
534 ret = rdma_bind_addr(listen_id, test.src_addr);
\r
536 printf("cmatose: bind address failed: 0x%x\n", ret);
\r
540 ret = rdma_listen(listen_id, 0);
\r
542 printf("cmatose: failure trying to listen: 0x%x\n", ret);
\r
546 ret = connect_events();
\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
558 printf("completing sends\n");
\r
559 ret = poll_cqs(SEND_CQ_INDEX);
\r
563 printf("receiving data transfers\n");
\r
564 ret = poll_cqs(RECV_CQ_INDEX);
\r
567 printf("data transfers complete\n");
\r
572 ret = migrate_channel(listen_id);
\r
577 printf("cmatose: disconnecting\n");
\r
578 for (i = 0; i < connections; i++) {
\r
579 if (!test.nodes[i].connected)
\r
582 test.nodes[i].connected = 0;
\r
583 rdma_disconnect(test.nodes[i].cma_id);
\r
586 ret = disconnect_events();
\r
588 printf("disconnected\n");
\r
591 rdma_destroy_id(listen_id);
\r
595 static int run_client(void)
\r
599 printf("cmatose: starting client\n");
\r
601 ret = get_addr(src_addr, &test.src_in);
\r
606 ret = get_addr(dst_addr, &test.dst_in);
\r
610 test.dst_in.sin_port = port;
\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
618 printf("cmatose: failure getting addr: 0x%x\n", ret);
\r
624 ret = connect_events();
\r
628 if (message_count) {
\r
629 printf("receiving data transfers\n");
\r
630 ret = poll_cqs(RECV_CQ_INDEX);
\r
634 printf("sending replies\n");
\r
635 for (i = 0; i < connections; i++) {
\r
636 ret = post_sends(&test.nodes[i]);
\r
641 printf("data transfers complete\n");
\r
647 ret = migrate_channel(NULL);
\r
652 ret2 = disconnect_events();
\r
659 int __cdecl main(int argc, char **argv)
\r
663 while ((op = getopt(argc, argv, "s:b:c:C:S:t:p:m")) != -1) {
\r
672 connections = atoi(optarg);
\r
675 message_count = atoi(optarg);
\r
678 message_size = atoi(optarg);
\r
682 tos = (uint8_t) atoi(optarg);
\r
685 port = (uint16_t) atoi(optarg);
\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
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
709 test.channel = rdma_create_event_channel();
\r
710 if (!test.channel) {
\r
711 printf("failed to create event channel\n");
\r
719 ret = run_client();
\r
721 ret = run_server();
\r
723 printf("test complete\n");
\r
725 rdma_destroy_event_channel(test.channel);
\r
727 printf("return status 0x%x\n", ret);
\r