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