1*aa0a1e58SJeff Roberson /* 2*aa0a1e58SJeff Roberson * Copyright (c) 2005 Ammasso, Inc. All rights reserved. 3*aa0a1e58SJeff Roberson * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. 4*aa0a1e58SJeff Roberson * 5*aa0a1e58SJeff Roberson * This software is available to you under a choice of one of two 6*aa0a1e58SJeff Roberson * licenses. You may choose to be licensed under the terms of the GNU 7*aa0a1e58SJeff Roberson * General Public License (GPL) Version 2, available from the file 8*aa0a1e58SJeff Roberson * COPYING in the main directory of this source tree, or the 9*aa0a1e58SJeff Roberson * OpenIB.org BSD license below: 10*aa0a1e58SJeff Roberson * 11*aa0a1e58SJeff Roberson * Redistribution and use in source and binary forms, with or 12*aa0a1e58SJeff Roberson * without modification, are permitted provided that the following 13*aa0a1e58SJeff Roberson * conditions are met: 14*aa0a1e58SJeff Roberson * 15*aa0a1e58SJeff Roberson * - Redistributions of source code must retain the above 16*aa0a1e58SJeff Roberson * copyright notice, this list of conditions and the following 17*aa0a1e58SJeff Roberson * disclaimer. 18*aa0a1e58SJeff Roberson * 19*aa0a1e58SJeff Roberson * - Redistributions in binary form must reproduce the above 20*aa0a1e58SJeff Roberson * copyright notice, this list of conditions and the following 21*aa0a1e58SJeff Roberson * disclaimer in the documentation and/or other materials 22*aa0a1e58SJeff Roberson * provided with the distribution. 23*aa0a1e58SJeff Roberson * 24*aa0a1e58SJeff Roberson * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25*aa0a1e58SJeff Roberson * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26*aa0a1e58SJeff Roberson * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27*aa0a1e58SJeff Roberson * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28*aa0a1e58SJeff Roberson * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29*aa0a1e58SJeff Roberson * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30*aa0a1e58SJeff Roberson * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31*aa0a1e58SJeff Roberson * SOFTWARE. 32*aa0a1e58SJeff Roberson */ 33*aa0a1e58SJeff Roberson 34*aa0a1e58SJeff Roberson #include <getopt.h> 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 <semaphore.h> 45*aa0a1e58SJeff Roberson #include <arpa/inet.h> 46*aa0a1e58SJeff Roberson #include <pthread.h> 47*aa0a1e58SJeff Roberson #include <inttypes.h> 48*aa0a1e58SJeff Roberson 49*aa0a1e58SJeff Roberson #include <rdma/rdma_cma.h> 50*aa0a1e58SJeff Roberson #include <infiniband/arch.h> 51*aa0a1e58SJeff Roberson 52*aa0a1e58SJeff Roberson static int debug = 0; 53*aa0a1e58SJeff Roberson #define DEBUG_LOG if (debug) printf 54*aa0a1e58SJeff Roberson 55*aa0a1e58SJeff Roberson /* 56*aa0a1e58SJeff Roberson * rping "ping/pong" loop: 57*aa0a1e58SJeff Roberson * client sends source rkey/addr/len 58*aa0a1e58SJeff Roberson * server receives source rkey/add/len 59*aa0a1e58SJeff Roberson * server rdma reads "ping" data from source 60*aa0a1e58SJeff Roberson * server sends "go ahead" on rdma read completion 61*aa0a1e58SJeff Roberson * client sends sink rkey/addr/len 62*aa0a1e58SJeff Roberson * server receives sink rkey/addr/len 63*aa0a1e58SJeff Roberson * server rdma writes "pong" data to sink 64*aa0a1e58SJeff Roberson * server sends "go ahead" on rdma write completion 65*aa0a1e58SJeff Roberson * <repeat loop> 66*aa0a1e58SJeff Roberson */ 67*aa0a1e58SJeff Roberson 68*aa0a1e58SJeff Roberson /* 69*aa0a1e58SJeff Roberson * These states are used to signal events between the completion handler 70*aa0a1e58SJeff Roberson * and the main client or server thread. 71*aa0a1e58SJeff Roberson * 72*aa0a1e58SJeff Roberson * Once CONNECTED, they cycle through RDMA_READ_ADV, RDMA_WRITE_ADV, 73*aa0a1e58SJeff Roberson * and RDMA_WRITE_COMPLETE for each ping. 74*aa0a1e58SJeff Roberson */ 75*aa0a1e58SJeff Roberson enum test_state { 76*aa0a1e58SJeff Roberson IDLE = 1, 77*aa0a1e58SJeff Roberson CONNECT_REQUEST, 78*aa0a1e58SJeff Roberson ADDR_RESOLVED, 79*aa0a1e58SJeff Roberson ROUTE_RESOLVED, 80*aa0a1e58SJeff Roberson CONNECTED, 81*aa0a1e58SJeff Roberson RDMA_READ_ADV, 82*aa0a1e58SJeff Roberson RDMA_READ_COMPLETE, 83*aa0a1e58SJeff Roberson RDMA_WRITE_ADV, 84*aa0a1e58SJeff Roberson RDMA_WRITE_COMPLETE, 85*aa0a1e58SJeff Roberson ERROR 86*aa0a1e58SJeff Roberson }; 87*aa0a1e58SJeff Roberson 88*aa0a1e58SJeff Roberson struct rping_rdma_info { 89*aa0a1e58SJeff Roberson uint64_t buf; 90*aa0a1e58SJeff Roberson uint32_t rkey; 91*aa0a1e58SJeff Roberson uint32_t size; 92*aa0a1e58SJeff Roberson }; 93*aa0a1e58SJeff Roberson 94*aa0a1e58SJeff Roberson /* 95*aa0a1e58SJeff Roberson * Default max buffer size for IO... 96*aa0a1e58SJeff Roberson */ 97*aa0a1e58SJeff Roberson #define RPING_BUFSIZE 64*1024 98*aa0a1e58SJeff Roberson #define RPING_SQ_DEPTH 16 99*aa0a1e58SJeff Roberson 100*aa0a1e58SJeff Roberson /* Default string for print data and 101*aa0a1e58SJeff Roberson * minimum buffer size 102*aa0a1e58SJeff Roberson */ 103*aa0a1e58SJeff Roberson #define _stringify( _x ) # _x 104*aa0a1e58SJeff Roberson #define stringify( _x ) _stringify( _x ) 105*aa0a1e58SJeff Roberson 106*aa0a1e58SJeff Roberson #define RPING_MSG_FMT "rdma-ping-%d: " 107*aa0a1e58SJeff Roberson #define RPING_MIN_BUFSIZE sizeof(stringify(INT_MAX)) + sizeof(RPING_MSG_FMT) 108*aa0a1e58SJeff Roberson 109*aa0a1e58SJeff Roberson /* 110*aa0a1e58SJeff Roberson * Control block struct. 111*aa0a1e58SJeff Roberson */ 112*aa0a1e58SJeff Roberson struct rping_cb { 113*aa0a1e58SJeff Roberson int server; /* 0 iff client */ 114*aa0a1e58SJeff Roberson pthread_t cqthread; 115*aa0a1e58SJeff Roberson pthread_t persistent_server_thread; 116*aa0a1e58SJeff Roberson struct ibv_comp_channel *channel; 117*aa0a1e58SJeff Roberson struct ibv_cq *cq; 118*aa0a1e58SJeff Roberson struct ibv_pd *pd; 119*aa0a1e58SJeff Roberson struct ibv_qp *qp; 120*aa0a1e58SJeff Roberson 121*aa0a1e58SJeff Roberson struct ibv_recv_wr rq_wr; /* recv work request record */ 122*aa0a1e58SJeff Roberson struct ibv_sge recv_sgl; /* recv single SGE */ 123*aa0a1e58SJeff Roberson struct rping_rdma_info recv_buf;/* malloc'd buffer */ 124*aa0a1e58SJeff Roberson struct ibv_mr *recv_mr; /* MR associated with this buffer */ 125*aa0a1e58SJeff Roberson 126*aa0a1e58SJeff Roberson struct ibv_send_wr sq_wr; /* send work request record */ 127*aa0a1e58SJeff Roberson struct ibv_sge send_sgl; 128*aa0a1e58SJeff Roberson struct rping_rdma_info send_buf;/* single send buf */ 129*aa0a1e58SJeff Roberson struct ibv_mr *send_mr; 130*aa0a1e58SJeff Roberson 131*aa0a1e58SJeff Roberson struct ibv_send_wr rdma_sq_wr; /* rdma work request record */ 132*aa0a1e58SJeff Roberson struct ibv_sge rdma_sgl; /* rdma single SGE */ 133*aa0a1e58SJeff Roberson char *rdma_buf; /* used as rdma sink */ 134*aa0a1e58SJeff Roberson struct ibv_mr *rdma_mr; 135*aa0a1e58SJeff Roberson 136*aa0a1e58SJeff Roberson uint32_t remote_rkey; /* remote guys RKEY */ 137*aa0a1e58SJeff Roberson uint64_t remote_addr; /* remote guys TO */ 138*aa0a1e58SJeff Roberson uint32_t remote_len; /* remote guys LEN */ 139*aa0a1e58SJeff Roberson 140*aa0a1e58SJeff Roberson char *start_buf; /* rdma read src */ 141*aa0a1e58SJeff Roberson struct ibv_mr *start_mr; 142*aa0a1e58SJeff Roberson 143*aa0a1e58SJeff Roberson enum test_state state; /* used for cond/signalling */ 144*aa0a1e58SJeff Roberson sem_t sem; 145*aa0a1e58SJeff Roberson 146*aa0a1e58SJeff Roberson struct sockaddr_storage sin; 147*aa0a1e58SJeff Roberson uint16_t port; /* dst port in NBO */ 148*aa0a1e58SJeff Roberson int verbose; /* verbose logging */ 149*aa0a1e58SJeff Roberson int count; /* ping count */ 150*aa0a1e58SJeff Roberson int size; /* ping data size */ 151*aa0a1e58SJeff Roberson int validate; /* validate ping data */ 152*aa0a1e58SJeff Roberson 153*aa0a1e58SJeff Roberson /* CM stuff */ 154*aa0a1e58SJeff Roberson pthread_t cmthread; 155*aa0a1e58SJeff Roberson struct rdma_event_channel *cm_channel; 156*aa0a1e58SJeff Roberson struct rdma_cm_id *cm_id; /* connection on client side,*/ 157*aa0a1e58SJeff Roberson /* listener on service side. */ 158*aa0a1e58SJeff Roberson struct rdma_cm_id *child_cm_id; /* connection on server side */ 159*aa0a1e58SJeff Roberson }; 160*aa0a1e58SJeff Roberson 161*aa0a1e58SJeff Roberson static int rping_cma_event_handler(struct rdma_cm_id *cma_id, 162*aa0a1e58SJeff Roberson struct rdma_cm_event *event) 163*aa0a1e58SJeff Roberson { 164*aa0a1e58SJeff Roberson int ret = 0; 165*aa0a1e58SJeff Roberson struct rping_cb *cb = cma_id->context; 166*aa0a1e58SJeff Roberson 167*aa0a1e58SJeff Roberson DEBUG_LOG("cma_event type %s cma_id %p (%s)\n", 168*aa0a1e58SJeff Roberson rdma_event_str(event->event), cma_id, 169*aa0a1e58SJeff Roberson (cma_id == cb->cm_id) ? "parent" : "child"); 170*aa0a1e58SJeff Roberson 171*aa0a1e58SJeff Roberson switch (event->event) { 172*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_ADDR_RESOLVED: 173*aa0a1e58SJeff Roberson cb->state = ADDR_RESOLVED; 174*aa0a1e58SJeff Roberson ret = rdma_resolve_route(cma_id, 2000); 175*aa0a1e58SJeff Roberson if (ret) { 176*aa0a1e58SJeff Roberson cb->state = ERROR; 177*aa0a1e58SJeff Roberson perror("rdma_resolve_route"); 178*aa0a1e58SJeff Roberson sem_post(&cb->sem); 179*aa0a1e58SJeff Roberson } 180*aa0a1e58SJeff Roberson break; 181*aa0a1e58SJeff Roberson 182*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_ROUTE_RESOLVED: 183*aa0a1e58SJeff Roberson cb->state = ROUTE_RESOLVED; 184*aa0a1e58SJeff Roberson sem_post(&cb->sem); 185*aa0a1e58SJeff Roberson break; 186*aa0a1e58SJeff Roberson 187*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_CONNECT_REQUEST: 188*aa0a1e58SJeff Roberson cb->state = CONNECT_REQUEST; 189*aa0a1e58SJeff Roberson cb->child_cm_id = cma_id; 190*aa0a1e58SJeff Roberson DEBUG_LOG("child cma %p\n", cb->child_cm_id); 191*aa0a1e58SJeff Roberson sem_post(&cb->sem); 192*aa0a1e58SJeff Roberson break; 193*aa0a1e58SJeff Roberson 194*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_ESTABLISHED: 195*aa0a1e58SJeff Roberson DEBUG_LOG("ESTABLISHED\n"); 196*aa0a1e58SJeff Roberson 197*aa0a1e58SJeff Roberson /* 198*aa0a1e58SJeff Roberson * Server will wake up when first RECV completes. 199*aa0a1e58SJeff Roberson */ 200*aa0a1e58SJeff Roberson if (!cb->server) { 201*aa0a1e58SJeff Roberson cb->state = CONNECTED; 202*aa0a1e58SJeff Roberson } 203*aa0a1e58SJeff Roberson sem_post(&cb->sem); 204*aa0a1e58SJeff Roberson break; 205*aa0a1e58SJeff Roberson 206*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_ADDR_ERROR: 207*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_ROUTE_ERROR: 208*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_CONNECT_ERROR: 209*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_UNREACHABLE: 210*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_REJECTED: 211*aa0a1e58SJeff Roberson fprintf(stderr, "cma event %s, error %d\n", 212*aa0a1e58SJeff Roberson rdma_event_str(event->event), event->status); 213*aa0a1e58SJeff Roberson sem_post(&cb->sem); 214*aa0a1e58SJeff Roberson ret = -1; 215*aa0a1e58SJeff Roberson break; 216*aa0a1e58SJeff Roberson 217*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_DISCONNECTED: 218*aa0a1e58SJeff Roberson fprintf(stderr, "%s DISCONNECT EVENT...\n", 219*aa0a1e58SJeff Roberson cb->server ? "server" : "client"); 220*aa0a1e58SJeff Roberson sem_post(&cb->sem); 221*aa0a1e58SJeff Roberson break; 222*aa0a1e58SJeff Roberson 223*aa0a1e58SJeff Roberson case RDMA_CM_EVENT_DEVICE_REMOVAL: 224*aa0a1e58SJeff Roberson fprintf(stderr, "cma detected device removal!!!!\n"); 225*aa0a1e58SJeff Roberson ret = -1; 226*aa0a1e58SJeff Roberson break; 227*aa0a1e58SJeff Roberson 228*aa0a1e58SJeff Roberson default: 229*aa0a1e58SJeff Roberson fprintf(stderr, "unhandled event: %s, ignoring\n", 230*aa0a1e58SJeff Roberson rdma_event_str(event->event)); 231*aa0a1e58SJeff Roberson break; 232*aa0a1e58SJeff Roberson } 233*aa0a1e58SJeff Roberson 234*aa0a1e58SJeff Roberson return ret; 235*aa0a1e58SJeff Roberson } 236*aa0a1e58SJeff Roberson 237*aa0a1e58SJeff Roberson static int server_recv(struct rping_cb *cb, struct ibv_wc *wc) 238*aa0a1e58SJeff Roberson { 239*aa0a1e58SJeff Roberson if (wc->byte_len != sizeof(cb->recv_buf)) { 240*aa0a1e58SJeff Roberson fprintf(stderr, "Received bogus data, size %d\n", wc->byte_len); 241*aa0a1e58SJeff Roberson return -1; 242*aa0a1e58SJeff Roberson } 243*aa0a1e58SJeff Roberson 244*aa0a1e58SJeff Roberson cb->remote_rkey = ntohl(cb->recv_buf.rkey); 245*aa0a1e58SJeff Roberson cb->remote_addr = ntohll(cb->recv_buf.buf); 246*aa0a1e58SJeff Roberson cb->remote_len = ntohl(cb->recv_buf.size); 247*aa0a1e58SJeff Roberson DEBUG_LOG("Received rkey %x addr %" PRIx64 " len %d from peer\n", 248*aa0a1e58SJeff Roberson cb->remote_rkey, cb->remote_addr, cb->remote_len); 249*aa0a1e58SJeff Roberson 250*aa0a1e58SJeff Roberson if (cb->state <= CONNECTED || cb->state == RDMA_WRITE_COMPLETE) 251*aa0a1e58SJeff Roberson cb->state = RDMA_READ_ADV; 252*aa0a1e58SJeff Roberson else 253*aa0a1e58SJeff Roberson cb->state = RDMA_WRITE_ADV; 254*aa0a1e58SJeff Roberson 255*aa0a1e58SJeff Roberson return 0; 256*aa0a1e58SJeff Roberson } 257*aa0a1e58SJeff Roberson 258*aa0a1e58SJeff Roberson static int client_recv(struct rping_cb *cb, struct ibv_wc *wc) 259*aa0a1e58SJeff Roberson { 260*aa0a1e58SJeff Roberson if (wc->byte_len != sizeof(cb->recv_buf)) { 261*aa0a1e58SJeff Roberson fprintf(stderr, "Received bogus data, size %d\n", wc->byte_len); 262*aa0a1e58SJeff Roberson return -1; 263*aa0a1e58SJeff Roberson } 264*aa0a1e58SJeff Roberson 265*aa0a1e58SJeff Roberson if (cb->state == RDMA_READ_ADV) 266*aa0a1e58SJeff Roberson cb->state = RDMA_WRITE_ADV; 267*aa0a1e58SJeff Roberson else 268*aa0a1e58SJeff Roberson cb->state = RDMA_WRITE_COMPLETE; 269*aa0a1e58SJeff Roberson 270*aa0a1e58SJeff Roberson return 0; 271*aa0a1e58SJeff Roberson } 272*aa0a1e58SJeff Roberson 273*aa0a1e58SJeff Roberson static int rping_cq_event_handler(struct rping_cb *cb) 274*aa0a1e58SJeff Roberson { 275*aa0a1e58SJeff Roberson struct ibv_wc wc; 276*aa0a1e58SJeff Roberson struct ibv_recv_wr *bad_wr; 277*aa0a1e58SJeff Roberson int ret; 278*aa0a1e58SJeff Roberson 279*aa0a1e58SJeff Roberson while ((ret = ibv_poll_cq(cb->cq, 1, &wc)) == 1) { 280*aa0a1e58SJeff Roberson ret = 0; 281*aa0a1e58SJeff Roberson 282*aa0a1e58SJeff Roberson if (wc.status) { 283*aa0a1e58SJeff Roberson fprintf(stderr, "cq completion failed status %d\n", 284*aa0a1e58SJeff Roberson wc.status); 285*aa0a1e58SJeff Roberson if (wc.status != IBV_WC_WR_FLUSH_ERR) 286*aa0a1e58SJeff Roberson ret = -1; 287*aa0a1e58SJeff Roberson goto error; 288*aa0a1e58SJeff Roberson } 289*aa0a1e58SJeff Roberson 290*aa0a1e58SJeff Roberson switch (wc.opcode) { 291*aa0a1e58SJeff Roberson case IBV_WC_SEND: 292*aa0a1e58SJeff Roberson DEBUG_LOG("send completion\n"); 293*aa0a1e58SJeff Roberson break; 294*aa0a1e58SJeff Roberson 295*aa0a1e58SJeff Roberson case IBV_WC_RDMA_WRITE: 296*aa0a1e58SJeff Roberson DEBUG_LOG("rdma write completion\n"); 297*aa0a1e58SJeff Roberson cb->state = RDMA_WRITE_COMPLETE; 298*aa0a1e58SJeff Roberson sem_post(&cb->sem); 299*aa0a1e58SJeff Roberson break; 300*aa0a1e58SJeff Roberson 301*aa0a1e58SJeff Roberson case IBV_WC_RDMA_READ: 302*aa0a1e58SJeff Roberson DEBUG_LOG("rdma read completion\n"); 303*aa0a1e58SJeff Roberson cb->state = RDMA_READ_COMPLETE; 304*aa0a1e58SJeff Roberson sem_post(&cb->sem); 305*aa0a1e58SJeff Roberson break; 306*aa0a1e58SJeff Roberson 307*aa0a1e58SJeff Roberson case IBV_WC_RECV: 308*aa0a1e58SJeff Roberson DEBUG_LOG("recv completion\n"); 309*aa0a1e58SJeff Roberson ret = cb->server ? server_recv(cb, &wc) : 310*aa0a1e58SJeff Roberson client_recv(cb, &wc); 311*aa0a1e58SJeff Roberson if (ret) { 312*aa0a1e58SJeff Roberson fprintf(stderr, "recv wc error: %d\n", ret); 313*aa0a1e58SJeff Roberson goto error; 314*aa0a1e58SJeff Roberson } 315*aa0a1e58SJeff Roberson 316*aa0a1e58SJeff Roberson ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); 317*aa0a1e58SJeff Roberson if (ret) { 318*aa0a1e58SJeff Roberson fprintf(stderr, "post recv error: %d\n", ret); 319*aa0a1e58SJeff Roberson goto error; 320*aa0a1e58SJeff Roberson } 321*aa0a1e58SJeff Roberson sem_post(&cb->sem); 322*aa0a1e58SJeff Roberson break; 323*aa0a1e58SJeff Roberson 324*aa0a1e58SJeff Roberson default: 325*aa0a1e58SJeff Roberson DEBUG_LOG("unknown!!!!! completion\n"); 326*aa0a1e58SJeff Roberson ret = -1; 327*aa0a1e58SJeff Roberson goto error; 328*aa0a1e58SJeff Roberson } 329*aa0a1e58SJeff Roberson } 330*aa0a1e58SJeff Roberson if (ret) { 331*aa0a1e58SJeff Roberson fprintf(stderr, "poll error %d\n", ret); 332*aa0a1e58SJeff Roberson goto error; 333*aa0a1e58SJeff Roberson } 334*aa0a1e58SJeff Roberson return 0; 335*aa0a1e58SJeff Roberson 336*aa0a1e58SJeff Roberson error: 337*aa0a1e58SJeff Roberson cb->state = ERROR; 338*aa0a1e58SJeff Roberson sem_post(&cb->sem); 339*aa0a1e58SJeff Roberson return ret; 340*aa0a1e58SJeff Roberson } 341*aa0a1e58SJeff Roberson 342*aa0a1e58SJeff Roberson static int rping_accept(struct rping_cb *cb) 343*aa0a1e58SJeff Roberson { 344*aa0a1e58SJeff Roberson struct rdma_conn_param conn_param; 345*aa0a1e58SJeff Roberson int ret; 346*aa0a1e58SJeff Roberson 347*aa0a1e58SJeff Roberson DEBUG_LOG("accepting client connection request\n"); 348*aa0a1e58SJeff Roberson 349*aa0a1e58SJeff Roberson memset(&conn_param, 0, sizeof conn_param); 350*aa0a1e58SJeff Roberson conn_param.responder_resources = 1; 351*aa0a1e58SJeff Roberson conn_param.initiator_depth = 1; 352*aa0a1e58SJeff Roberson 353*aa0a1e58SJeff Roberson ret = rdma_accept(cb->child_cm_id, &conn_param); 354*aa0a1e58SJeff Roberson if (ret) { 355*aa0a1e58SJeff Roberson perror("rdma_accept"); 356*aa0a1e58SJeff Roberson return ret; 357*aa0a1e58SJeff Roberson } 358*aa0a1e58SJeff Roberson 359*aa0a1e58SJeff Roberson sem_wait(&cb->sem); 360*aa0a1e58SJeff Roberson if (cb->state == ERROR) { 361*aa0a1e58SJeff Roberson fprintf(stderr, "wait for CONNECTED state %d\n", cb->state); 362*aa0a1e58SJeff Roberson return -1; 363*aa0a1e58SJeff Roberson } 364*aa0a1e58SJeff Roberson return 0; 365*aa0a1e58SJeff Roberson } 366*aa0a1e58SJeff Roberson 367*aa0a1e58SJeff Roberson static void rping_setup_wr(struct rping_cb *cb) 368*aa0a1e58SJeff Roberson { 369*aa0a1e58SJeff Roberson cb->recv_sgl.addr = (uint64_t) (unsigned long) &cb->recv_buf; 370*aa0a1e58SJeff Roberson cb->recv_sgl.length = sizeof cb->recv_buf; 371*aa0a1e58SJeff Roberson cb->recv_sgl.lkey = cb->recv_mr->lkey; 372*aa0a1e58SJeff Roberson cb->rq_wr.sg_list = &cb->recv_sgl; 373*aa0a1e58SJeff Roberson cb->rq_wr.num_sge = 1; 374*aa0a1e58SJeff Roberson 375*aa0a1e58SJeff Roberson cb->send_sgl.addr = (uint64_t) (unsigned long) &cb->send_buf; 376*aa0a1e58SJeff Roberson cb->send_sgl.length = sizeof cb->send_buf; 377*aa0a1e58SJeff Roberson cb->send_sgl.lkey = cb->send_mr->lkey; 378*aa0a1e58SJeff Roberson 379*aa0a1e58SJeff Roberson cb->sq_wr.opcode = IBV_WR_SEND; 380*aa0a1e58SJeff Roberson cb->sq_wr.send_flags = IBV_SEND_SIGNALED; 381*aa0a1e58SJeff Roberson cb->sq_wr.sg_list = &cb->send_sgl; 382*aa0a1e58SJeff Roberson cb->sq_wr.num_sge = 1; 383*aa0a1e58SJeff Roberson 384*aa0a1e58SJeff Roberson cb->rdma_sgl.addr = (uint64_t) (unsigned long) cb->rdma_buf; 385*aa0a1e58SJeff Roberson cb->rdma_sgl.lkey = cb->rdma_mr->lkey; 386*aa0a1e58SJeff Roberson cb->rdma_sq_wr.send_flags = IBV_SEND_SIGNALED; 387*aa0a1e58SJeff Roberson cb->rdma_sq_wr.sg_list = &cb->rdma_sgl; 388*aa0a1e58SJeff Roberson cb->rdma_sq_wr.num_sge = 1; 389*aa0a1e58SJeff Roberson } 390*aa0a1e58SJeff Roberson 391*aa0a1e58SJeff Roberson static int rping_setup_buffers(struct rping_cb *cb) 392*aa0a1e58SJeff Roberson { 393*aa0a1e58SJeff Roberson int ret; 394*aa0a1e58SJeff Roberson 395*aa0a1e58SJeff Roberson DEBUG_LOG("rping_setup_buffers called on cb %p\n", cb); 396*aa0a1e58SJeff Roberson 397*aa0a1e58SJeff Roberson cb->recv_mr = ibv_reg_mr(cb->pd, &cb->recv_buf, sizeof cb->recv_buf, 398*aa0a1e58SJeff Roberson IBV_ACCESS_LOCAL_WRITE); 399*aa0a1e58SJeff Roberson if (!cb->recv_mr) { 400*aa0a1e58SJeff Roberson fprintf(stderr, "recv_buf reg_mr failed\n"); 401*aa0a1e58SJeff Roberson return errno; 402*aa0a1e58SJeff Roberson } 403*aa0a1e58SJeff Roberson 404*aa0a1e58SJeff Roberson cb->send_mr = ibv_reg_mr(cb->pd, &cb->send_buf, sizeof cb->send_buf, 0); 405*aa0a1e58SJeff Roberson if (!cb->send_mr) { 406*aa0a1e58SJeff Roberson fprintf(stderr, "send_buf reg_mr failed\n"); 407*aa0a1e58SJeff Roberson ret = errno; 408*aa0a1e58SJeff Roberson goto err1; 409*aa0a1e58SJeff Roberson } 410*aa0a1e58SJeff Roberson 411*aa0a1e58SJeff Roberson cb->rdma_buf = malloc(cb->size); 412*aa0a1e58SJeff Roberson if (!cb->rdma_buf) { 413*aa0a1e58SJeff Roberson fprintf(stderr, "rdma_buf malloc failed\n"); 414*aa0a1e58SJeff Roberson ret = -ENOMEM; 415*aa0a1e58SJeff Roberson goto err2; 416*aa0a1e58SJeff Roberson } 417*aa0a1e58SJeff Roberson 418*aa0a1e58SJeff Roberson cb->rdma_mr = ibv_reg_mr(cb->pd, cb->rdma_buf, cb->size, 419*aa0a1e58SJeff Roberson IBV_ACCESS_LOCAL_WRITE | 420*aa0a1e58SJeff Roberson IBV_ACCESS_REMOTE_READ | 421*aa0a1e58SJeff Roberson IBV_ACCESS_REMOTE_WRITE); 422*aa0a1e58SJeff Roberson if (!cb->rdma_mr) { 423*aa0a1e58SJeff Roberson fprintf(stderr, "rdma_buf reg_mr failed\n"); 424*aa0a1e58SJeff Roberson ret = errno; 425*aa0a1e58SJeff Roberson goto err3; 426*aa0a1e58SJeff Roberson } 427*aa0a1e58SJeff Roberson 428*aa0a1e58SJeff Roberson if (!cb->server) { 429*aa0a1e58SJeff Roberson cb->start_buf = malloc(cb->size); 430*aa0a1e58SJeff Roberson if (!cb->start_buf) { 431*aa0a1e58SJeff Roberson fprintf(stderr, "start_buf malloc failed\n"); 432*aa0a1e58SJeff Roberson ret = -ENOMEM; 433*aa0a1e58SJeff Roberson goto err4; 434*aa0a1e58SJeff Roberson } 435*aa0a1e58SJeff Roberson 436*aa0a1e58SJeff Roberson cb->start_mr = ibv_reg_mr(cb->pd, cb->start_buf, cb->size, 437*aa0a1e58SJeff Roberson IBV_ACCESS_LOCAL_WRITE | 438*aa0a1e58SJeff Roberson IBV_ACCESS_REMOTE_READ | 439*aa0a1e58SJeff Roberson IBV_ACCESS_REMOTE_WRITE); 440*aa0a1e58SJeff Roberson if (!cb->start_mr) { 441*aa0a1e58SJeff Roberson fprintf(stderr, "start_buf reg_mr failed\n"); 442*aa0a1e58SJeff Roberson ret = errno; 443*aa0a1e58SJeff Roberson goto err5; 444*aa0a1e58SJeff Roberson } 445*aa0a1e58SJeff Roberson } 446*aa0a1e58SJeff Roberson 447*aa0a1e58SJeff Roberson rping_setup_wr(cb); 448*aa0a1e58SJeff Roberson DEBUG_LOG("allocated & registered buffers...\n"); 449*aa0a1e58SJeff Roberson return 0; 450*aa0a1e58SJeff Roberson 451*aa0a1e58SJeff Roberson err5: 452*aa0a1e58SJeff Roberson free(cb->start_buf); 453*aa0a1e58SJeff Roberson err4: 454*aa0a1e58SJeff Roberson ibv_dereg_mr(cb->rdma_mr); 455*aa0a1e58SJeff Roberson err3: 456*aa0a1e58SJeff Roberson free(cb->rdma_buf); 457*aa0a1e58SJeff Roberson err2: 458*aa0a1e58SJeff Roberson ibv_dereg_mr(cb->send_mr); 459*aa0a1e58SJeff Roberson err1: 460*aa0a1e58SJeff Roberson ibv_dereg_mr(cb->recv_mr); 461*aa0a1e58SJeff Roberson return ret; 462*aa0a1e58SJeff Roberson } 463*aa0a1e58SJeff Roberson 464*aa0a1e58SJeff Roberson static void rping_free_buffers(struct rping_cb *cb) 465*aa0a1e58SJeff Roberson { 466*aa0a1e58SJeff Roberson DEBUG_LOG("rping_free_buffers called on cb %p\n", cb); 467*aa0a1e58SJeff Roberson ibv_dereg_mr(cb->recv_mr); 468*aa0a1e58SJeff Roberson ibv_dereg_mr(cb->send_mr); 469*aa0a1e58SJeff Roberson ibv_dereg_mr(cb->rdma_mr); 470*aa0a1e58SJeff Roberson free(cb->rdma_buf); 471*aa0a1e58SJeff Roberson if (!cb->server) { 472*aa0a1e58SJeff Roberson ibv_dereg_mr(cb->start_mr); 473*aa0a1e58SJeff Roberson free(cb->start_buf); 474*aa0a1e58SJeff Roberson } 475*aa0a1e58SJeff Roberson } 476*aa0a1e58SJeff Roberson 477*aa0a1e58SJeff Roberson static int rping_create_qp(struct rping_cb *cb) 478*aa0a1e58SJeff Roberson { 479*aa0a1e58SJeff Roberson struct ibv_qp_init_attr init_attr; 480*aa0a1e58SJeff Roberson int ret; 481*aa0a1e58SJeff Roberson 482*aa0a1e58SJeff Roberson memset(&init_attr, 0, sizeof(init_attr)); 483*aa0a1e58SJeff Roberson init_attr.cap.max_send_wr = RPING_SQ_DEPTH; 484*aa0a1e58SJeff Roberson init_attr.cap.max_recv_wr = 2; 485*aa0a1e58SJeff Roberson init_attr.cap.max_recv_sge = 1; 486*aa0a1e58SJeff Roberson init_attr.cap.max_send_sge = 1; 487*aa0a1e58SJeff Roberson init_attr.qp_type = IBV_QPT_RC; 488*aa0a1e58SJeff Roberson init_attr.send_cq = cb->cq; 489*aa0a1e58SJeff Roberson init_attr.recv_cq = cb->cq; 490*aa0a1e58SJeff Roberson 491*aa0a1e58SJeff Roberson if (cb->server) { 492*aa0a1e58SJeff Roberson ret = rdma_create_qp(cb->child_cm_id, cb->pd, &init_attr); 493*aa0a1e58SJeff Roberson if (!ret) 494*aa0a1e58SJeff Roberson cb->qp = cb->child_cm_id->qp; 495*aa0a1e58SJeff Roberson } else { 496*aa0a1e58SJeff Roberson ret = rdma_create_qp(cb->cm_id, cb->pd, &init_attr); 497*aa0a1e58SJeff Roberson if (!ret) 498*aa0a1e58SJeff Roberson cb->qp = cb->cm_id->qp; 499*aa0a1e58SJeff Roberson } 500*aa0a1e58SJeff Roberson 501*aa0a1e58SJeff Roberson return ret; 502*aa0a1e58SJeff Roberson } 503*aa0a1e58SJeff Roberson 504*aa0a1e58SJeff Roberson static void rping_free_qp(struct rping_cb *cb) 505*aa0a1e58SJeff Roberson { 506*aa0a1e58SJeff Roberson ibv_destroy_qp(cb->qp); 507*aa0a1e58SJeff Roberson ibv_destroy_cq(cb->cq); 508*aa0a1e58SJeff Roberson ibv_destroy_comp_channel(cb->channel); 509*aa0a1e58SJeff Roberson ibv_dealloc_pd(cb->pd); 510*aa0a1e58SJeff Roberson } 511*aa0a1e58SJeff Roberson 512*aa0a1e58SJeff Roberson static int rping_setup_qp(struct rping_cb *cb, struct rdma_cm_id *cm_id) 513*aa0a1e58SJeff Roberson { 514*aa0a1e58SJeff Roberson int ret; 515*aa0a1e58SJeff Roberson 516*aa0a1e58SJeff Roberson cb->pd = ibv_alloc_pd(cm_id->verbs); 517*aa0a1e58SJeff Roberson if (!cb->pd) { 518*aa0a1e58SJeff Roberson fprintf(stderr, "ibv_alloc_pd failed\n"); 519*aa0a1e58SJeff Roberson return errno; 520*aa0a1e58SJeff Roberson } 521*aa0a1e58SJeff Roberson DEBUG_LOG("created pd %p\n", cb->pd); 522*aa0a1e58SJeff Roberson 523*aa0a1e58SJeff Roberson cb->channel = ibv_create_comp_channel(cm_id->verbs); 524*aa0a1e58SJeff Roberson if (!cb->channel) { 525*aa0a1e58SJeff Roberson fprintf(stderr, "ibv_create_comp_channel failed\n"); 526*aa0a1e58SJeff Roberson ret = errno; 527*aa0a1e58SJeff Roberson goto err1; 528*aa0a1e58SJeff Roberson } 529*aa0a1e58SJeff Roberson DEBUG_LOG("created channel %p\n", cb->channel); 530*aa0a1e58SJeff Roberson 531*aa0a1e58SJeff Roberson cb->cq = ibv_create_cq(cm_id->verbs, RPING_SQ_DEPTH * 2, cb, 532*aa0a1e58SJeff Roberson cb->channel, 0); 533*aa0a1e58SJeff Roberson if (!cb->cq) { 534*aa0a1e58SJeff Roberson fprintf(stderr, "ibv_create_cq failed\n"); 535*aa0a1e58SJeff Roberson ret = errno; 536*aa0a1e58SJeff Roberson goto err2; 537*aa0a1e58SJeff Roberson } 538*aa0a1e58SJeff Roberson DEBUG_LOG("created cq %p\n", cb->cq); 539*aa0a1e58SJeff Roberson 540*aa0a1e58SJeff Roberson ret = ibv_req_notify_cq(cb->cq, 0); 541*aa0a1e58SJeff Roberson if (ret) { 542*aa0a1e58SJeff Roberson fprintf(stderr, "ibv_create_cq failed\n"); 543*aa0a1e58SJeff Roberson ret = errno; 544*aa0a1e58SJeff Roberson goto err3; 545*aa0a1e58SJeff Roberson } 546*aa0a1e58SJeff Roberson 547*aa0a1e58SJeff Roberson ret = rping_create_qp(cb); 548*aa0a1e58SJeff Roberson if (ret) { 549*aa0a1e58SJeff Roberson perror("rdma_create_qp"); 550*aa0a1e58SJeff Roberson goto err3; 551*aa0a1e58SJeff Roberson } 552*aa0a1e58SJeff Roberson DEBUG_LOG("created qp %p\n", cb->qp); 553*aa0a1e58SJeff Roberson return 0; 554*aa0a1e58SJeff Roberson 555*aa0a1e58SJeff Roberson err3: 556*aa0a1e58SJeff Roberson ibv_destroy_cq(cb->cq); 557*aa0a1e58SJeff Roberson err2: 558*aa0a1e58SJeff Roberson ibv_destroy_comp_channel(cb->channel); 559*aa0a1e58SJeff Roberson err1: 560*aa0a1e58SJeff Roberson ibv_dealloc_pd(cb->pd); 561*aa0a1e58SJeff Roberson return ret; 562*aa0a1e58SJeff Roberson } 563*aa0a1e58SJeff Roberson 564*aa0a1e58SJeff Roberson static void *cm_thread(void *arg) 565*aa0a1e58SJeff Roberson { 566*aa0a1e58SJeff Roberson struct rping_cb *cb = arg; 567*aa0a1e58SJeff Roberson struct rdma_cm_event *event; 568*aa0a1e58SJeff Roberson int ret; 569*aa0a1e58SJeff Roberson 570*aa0a1e58SJeff Roberson while (1) { 571*aa0a1e58SJeff Roberson ret = rdma_get_cm_event(cb->cm_channel, &event); 572*aa0a1e58SJeff Roberson if (ret) { 573*aa0a1e58SJeff Roberson perror("rdma_get_cm_event"); 574*aa0a1e58SJeff Roberson exit(ret); 575*aa0a1e58SJeff Roberson } 576*aa0a1e58SJeff Roberson ret = rping_cma_event_handler(event->id, event); 577*aa0a1e58SJeff Roberson rdma_ack_cm_event(event); 578*aa0a1e58SJeff Roberson if (ret) 579*aa0a1e58SJeff Roberson exit(ret); 580*aa0a1e58SJeff Roberson } 581*aa0a1e58SJeff Roberson } 582*aa0a1e58SJeff Roberson 583*aa0a1e58SJeff Roberson static void *cq_thread(void *arg) 584*aa0a1e58SJeff Roberson { 585*aa0a1e58SJeff Roberson struct rping_cb *cb = arg; 586*aa0a1e58SJeff Roberson struct ibv_cq *ev_cq; 587*aa0a1e58SJeff Roberson void *ev_ctx; 588*aa0a1e58SJeff Roberson int ret; 589*aa0a1e58SJeff Roberson 590*aa0a1e58SJeff Roberson DEBUG_LOG("cq_thread started.\n"); 591*aa0a1e58SJeff Roberson 592*aa0a1e58SJeff Roberson while (1) { 593*aa0a1e58SJeff Roberson pthread_testcancel(); 594*aa0a1e58SJeff Roberson 595*aa0a1e58SJeff Roberson ret = ibv_get_cq_event(cb->channel, &ev_cq, &ev_ctx); 596*aa0a1e58SJeff Roberson if (ret) { 597*aa0a1e58SJeff Roberson fprintf(stderr, "Failed to get cq event!\n"); 598*aa0a1e58SJeff Roberson pthread_exit(NULL); 599*aa0a1e58SJeff Roberson } 600*aa0a1e58SJeff Roberson if (ev_cq != cb->cq) { 601*aa0a1e58SJeff Roberson fprintf(stderr, "Unknown CQ!\n"); 602*aa0a1e58SJeff Roberson pthread_exit(NULL); 603*aa0a1e58SJeff Roberson } 604*aa0a1e58SJeff Roberson ret = ibv_req_notify_cq(cb->cq, 0); 605*aa0a1e58SJeff Roberson if (ret) { 606*aa0a1e58SJeff Roberson fprintf(stderr, "Failed to set notify!\n"); 607*aa0a1e58SJeff Roberson pthread_exit(NULL); 608*aa0a1e58SJeff Roberson } 609*aa0a1e58SJeff Roberson ret = rping_cq_event_handler(cb); 610*aa0a1e58SJeff Roberson ibv_ack_cq_events(cb->cq, 1); 611*aa0a1e58SJeff Roberson if (ret) 612*aa0a1e58SJeff Roberson pthread_exit(NULL); 613*aa0a1e58SJeff Roberson } 614*aa0a1e58SJeff Roberson } 615*aa0a1e58SJeff Roberson 616*aa0a1e58SJeff Roberson static void rping_format_send(struct rping_cb *cb, char *buf, struct ibv_mr *mr) 617*aa0a1e58SJeff Roberson { 618*aa0a1e58SJeff Roberson struct rping_rdma_info *info = &cb->send_buf; 619*aa0a1e58SJeff Roberson 620*aa0a1e58SJeff Roberson info->buf = htonll((uint64_t) (unsigned long) buf); 621*aa0a1e58SJeff Roberson info->rkey = htonl(mr->rkey); 622*aa0a1e58SJeff Roberson info->size = htonl(cb->size); 623*aa0a1e58SJeff Roberson 624*aa0a1e58SJeff Roberson DEBUG_LOG("RDMA addr %" PRIx64" rkey %x len %d\n", 625*aa0a1e58SJeff Roberson ntohll(info->buf), ntohl(info->rkey), ntohl(info->size)); 626*aa0a1e58SJeff Roberson } 627*aa0a1e58SJeff Roberson 628*aa0a1e58SJeff Roberson static int rping_test_server(struct rping_cb *cb) 629*aa0a1e58SJeff Roberson { 630*aa0a1e58SJeff Roberson struct ibv_send_wr *bad_wr; 631*aa0a1e58SJeff Roberson int ret; 632*aa0a1e58SJeff Roberson 633*aa0a1e58SJeff Roberson while (1) { 634*aa0a1e58SJeff Roberson /* Wait for client's Start STAG/TO/Len */ 635*aa0a1e58SJeff Roberson sem_wait(&cb->sem); 636*aa0a1e58SJeff Roberson if (cb->state != RDMA_READ_ADV) { 637*aa0a1e58SJeff Roberson fprintf(stderr, "wait for RDMA_READ_ADV state %d\n", 638*aa0a1e58SJeff Roberson cb->state); 639*aa0a1e58SJeff Roberson ret = -1; 640*aa0a1e58SJeff Roberson break; 641*aa0a1e58SJeff Roberson } 642*aa0a1e58SJeff Roberson 643*aa0a1e58SJeff Roberson DEBUG_LOG("server received sink adv\n"); 644*aa0a1e58SJeff Roberson 645*aa0a1e58SJeff Roberson /* Issue RDMA Read. */ 646*aa0a1e58SJeff Roberson cb->rdma_sq_wr.opcode = IBV_WR_RDMA_READ; 647*aa0a1e58SJeff Roberson cb->rdma_sq_wr.wr.rdma.rkey = cb->remote_rkey; 648*aa0a1e58SJeff Roberson cb->rdma_sq_wr.wr.rdma.remote_addr = cb->remote_addr; 649*aa0a1e58SJeff Roberson cb->rdma_sq_wr.sg_list->length = cb->remote_len; 650*aa0a1e58SJeff Roberson 651*aa0a1e58SJeff Roberson ret = ibv_post_send(cb->qp, &cb->rdma_sq_wr, &bad_wr); 652*aa0a1e58SJeff Roberson if (ret) { 653*aa0a1e58SJeff Roberson fprintf(stderr, "post send error %d\n", ret); 654*aa0a1e58SJeff Roberson break; 655*aa0a1e58SJeff Roberson } 656*aa0a1e58SJeff Roberson DEBUG_LOG("server posted rdma read req \n"); 657*aa0a1e58SJeff Roberson 658*aa0a1e58SJeff Roberson /* Wait for read completion */ 659*aa0a1e58SJeff Roberson sem_wait(&cb->sem); 660*aa0a1e58SJeff Roberson if (cb->state != RDMA_READ_COMPLETE) { 661*aa0a1e58SJeff Roberson fprintf(stderr, "wait for RDMA_READ_COMPLETE state %d\n", 662*aa0a1e58SJeff Roberson cb->state); 663*aa0a1e58SJeff Roberson ret = -1; 664*aa0a1e58SJeff Roberson break; 665*aa0a1e58SJeff Roberson } 666*aa0a1e58SJeff Roberson DEBUG_LOG("server received read complete\n"); 667*aa0a1e58SJeff Roberson 668*aa0a1e58SJeff Roberson /* Display data in recv buf */ 669*aa0a1e58SJeff Roberson if (cb->verbose) 670*aa0a1e58SJeff Roberson printf("server ping data: %s\n", cb->rdma_buf); 671*aa0a1e58SJeff Roberson 672*aa0a1e58SJeff Roberson /* Tell client to continue */ 673*aa0a1e58SJeff Roberson ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); 674*aa0a1e58SJeff Roberson if (ret) { 675*aa0a1e58SJeff Roberson fprintf(stderr, "post send error %d\n", ret); 676*aa0a1e58SJeff Roberson break; 677*aa0a1e58SJeff Roberson } 678*aa0a1e58SJeff Roberson DEBUG_LOG("server posted go ahead\n"); 679*aa0a1e58SJeff Roberson 680*aa0a1e58SJeff Roberson /* Wait for client's RDMA STAG/TO/Len */ 681*aa0a1e58SJeff Roberson sem_wait(&cb->sem); 682*aa0a1e58SJeff Roberson if (cb->state != RDMA_WRITE_ADV) { 683*aa0a1e58SJeff Roberson fprintf(stderr, "wait for RDMA_WRITE_ADV state %d\n", 684*aa0a1e58SJeff Roberson cb->state); 685*aa0a1e58SJeff Roberson ret = -1; 686*aa0a1e58SJeff Roberson break; 687*aa0a1e58SJeff Roberson } 688*aa0a1e58SJeff Roberson DEBUG_LOG("server received sink adv\n"); 689*aa0a1e58SJeff Roberson 690*aa0a1e58SJeff Roberson /* RDMA Write echo data */ 691*aa0a1e58SJeff Roberson cb->rdma_sq_wr.opcode = IBV_WR_RDMA_WRITE; 692*aa0a1e58SJeff Roberson cb->rdma_sq_wr.wr.rdma.rkey = cb->remote_rkey; 693*aa0a1e58SJeff Roberson cb->rdma_sq_wr.wr.rdma.remote_addr = cb->remote_addr; 694*aa0a1e58SJeff Roberson cb->rdma_sq_wr.sg_list->length = strlen(cb->rdma_buf) + 1; 695*aa0a1e58SJeff Roberson DEBUG_LOG("rdma write from lkey %x laddr %" PRIx64 " len %d\n", 696*aa0a1e58SJeff Roberson cb->rdma_sq_wr.sg_list->lkey, 697*aa0a1e58SJeff Roberson cb->rdma_sq_wr.sg_list->addr, 698*aa0a1e58SJeff Roberson cb->rdma_sq_wr.sg_list->length); 699*aa0a1e58SJeff Roberson 700*aa0a1e58SJeff Roberson ret = ibv_post_send(cb->qp, &cb->rdma_sq_wr, &bad_wr); 701*aa0a1e58SJeff Roberson if (ret) { 702*aa0a1e58SJeff Roberson fprintf(stderr, "post send error %d\n", ret); 703*aa0a1e58SJeff Roberson break; 704*aa0a1e58SJeff Roberson } 705*aa0a1e58SJeff Roberson 706*aa0a1e58SJeff Roberson /* Wait for completion */ 707*aa0a1e58SJeff Roberson ret = sem_wait(&cb->sem); 708*aa0a1e58SJeff Roberson if (cb->state != RDMA_WRITE_COMPLETE) { 709*aa0a1e58SJeff Roberson fprintf(stderr, "wait for RDMA_WRITE_COMPLETE state %d\n", 710*aa0a1e58SJeff Roberson cb->state); 711*aa0a1e58SJeff Roberson ret = -1; 712*aa0a1e58SJeff Roberson break; 713*aa0a1e58SJeff Roberson } 714*aa0a1e58SJeff Roberson DEBUG_LOG("server rdma write complete \n"); 715*aa0a1e58SJeff Roberson 716*aa0a1e58SJeff Roberson /* Tell client to begin again */ 717*aa0a1e58SJeff Roberson ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); 718*aa0a1e58SJeff Roberson if (ret) { 719*aa0a1e58SJeff Roberson fprintf(stderr, "post send error %d\n", ret); 720*aa0a1e58SJeff Roberson break; 721*aa0a1e58SJeff Roberson } 722*aa0a1e58SJeff Roberson DEBUG_LOG("server posted go ahead\n"); 723*aa0a1e58SJeff Roberson } 724*aa0a1e58SJeff Roberson 725*aa0a1e58SJeff Roberson return ret; 726*aa0a1e58SJeff Roberson } 727*aa0a1e58SJeff Roberson 728*aa0a1e58SJeff Roberson static int rping_bind_server(struct rping_cb *cb) 729*aa0a1e58SJeff Roberson { 730*aa0a1e58SJeff Roberson int ret; 731*aa0a1e58SJeff Roberson 732*aa0a1e58SJeff Roberson if (cb->sin.ss_family == AF_INET) 733*aa0a1e58SJeff Roberson ((struct sockaddr_in *) &cb->sin)->sin_port = cb->port; 734*aa0a1e58SJeff Roberson else 735*aa0a1e58SJeff Roberson ((struct sockaddr_in6 *) &cb->sin)->sin6_port = cb->port; 736*aa0a1e58SJeff Roberson 737*aa0a1e58SJeff Roberson ret = rdma_bind_addr(cb->cm_id, (struct sockaddr *) &cb->sin); 738*aa0a1e58SJeff Roberson if (ret) { 739*aa0a1e58SJeff Roberson perror("rdma_bind_addr"); 740*aa0a1e58SJeff Roberson return ret; 741*aa0a1e58SJeff Roberson } 742*aa0a1e58SJeff Roberson DEBUG_LOG("rdma_bind_addr successful\n"); 743*aa0a1e58SJeff Roberson 744*aa0a1e58SJeff Roberson DEBUG_LOG("rdma_listen\n"); 745*aa0a1e58SJeff Roberson ret = rdma_listen(cb->cm_id, 3); 746*aa0a1e58SJeff Roberson if (ret) { 747*aa0a1e58SJeff Roberson perror("rdma_listen"); 748*aa0a1e58SJeff Roberson return ret; 749*aa0a1e58SJeff Roberson } 750*aa0a1e58SJeff Roberson 751*aa0a1e58SJeff Roberson return 0; 752*aa0a1e58SJeff Roberson } 753*aa0a1e58SJeff Roberson 754*aa0a1e58SJeff Roberson static struct rping_cb *clone_cb(struct rping_cb *listening_cb) 755*aa0a1e58SJeff Roberson { 756*aa0a1e58SJeff Roberson struct rping_cb *cb = malloc(sizeof *cb); 757*aa0a1e58SJeff Roberson if (!cb) 758*aa0a1e58SJeff Roberson return NULL; 759*aa0a1e58SJeff Roberson *cb = *listening_cb; 760*aa0a1e58SJeff Roberson cb->child_cm_id->context = cb; 761*aa0a1e58SJeff Roberson return cb; 762*aa0a1e58SJeff Roberson } 763*aa0a1e58SJeff Roberson 764*aa0a1e58SJeff Roberson static void free_cb(struct rping_cb *cb) 765*aa0a1e58SJeff Roberson { 766*aa0a1e58SJeff Roberson free(cb); 767*aa0a1e58SJeff Roberson } 768*aa0a1e58SJeff Roberson 769*aa0a1e58SJeff Roberson static void *rping_persistent_server_thread(void *arg) 770*aa0a1e58SJeff Roberson { 771*aa0a1e58SJeff Roberson struct rping_cb *cb = arg; 772*aa0a1e58SJeff Roberson struct ibv_recv_wr *bad_wr; 773*aa0a1e58SJeff Roberson int ret; 774*aa0a1e58SJeff Roberson 775*aa0a1e58SJeff Roberson ret = rping_setup_qp(cb, cb->child_cm_id); 776*aa0a1e58SJeff Roberson if (ret) { 777*aa0a1e58SJeff Roberson fprintf(stderr, "setup_qp failed: %d\n", ret); 778*aa0a1e58SJeff Roberson goto err0; 779*aa0a1e58SJeff Roberson } 780*aa0a1e58SJeff Roberson 781*aa0a1e58SJeff Roberson ret = rping_setup_buffers(cb); 782*aa0a1e58SJeff Roberson if (ret) { 783*aa0a1e58SJeff Roberson fprintf(stderr, "rping_setup_buffers failed: %d\n", ret); 784*aa0a1e58SJeff Roberson goto err1; 785*aa0a1e58SJeff Roberson } 786*aa0a1e58SJeff Roberson 787*aa0a1e58SJeff Roberson ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); 788*aa0a1e58SJeff Roberson if (ret) { 789*aa0a1e58SJeff Roberson fprintf(stderr, "ibv_post_recv failed: %d\n", ret); 790*aa0a1e58SJeff Roberson goto err2; 791*aa0a1e58SJeff Roberson } 792*aa0a1e58SJeff Roberson 793*aa0a1e58SJeff Roberson pthread_create(&cb->cqthread, NULL, cq_thread, cb); 794*aa0a1e58SJeff Roberson 795*aa0a1e58SJeff Roberson ret = rping_accept(cb); 796*aa0a1e58SJeff Roberson if (ret) { 797*aa0a1e58SJeff Roberson fprintf(stderr, "connect error %d\n", ret); 798*aa0a1e58SJeff Roberson goto err3; 799*aa0a1e58SJeff Roberson } 800*aa0a1e58SJeff Roberson 801*aa0a1e58SJeff Roberson rping_test_server(cb); 802*aa0a1e58SJeff Roberson rdma_disconnect(cb->child_cm_id); 803*aa0a1e58SJeff Roberson rping_free_buffers(cb); 804*aa0a1e58SJeff Roberson rping_free_qp(cb); 805*aa0a1e58SJeff Roberson pthread_cancel(cb->cqthread); 806*aa0a1e58SJeff Roberson pthread_join(cb->cqthread, NULL); 807*aa0a1e58SJeff Roberson rdma_destroy_id(cb->child_cm_id); 808*aa0a1e58SJeff Roberson free_cb(cb); 809*aa0a1e58SJeff Roberson return NULL; 810*aa0a1e58SJeff Roberson err3: 811*aa0a1e58SJeff Roberson pthread_cancel(cb->cqthread); 812*aa0a1e58SJeff Roberson pthread_join(cb->cqthread, NULL); 813*aa0a1e58SJeff Roberson err2: 814*aa0a1e58SJeff Roberson rping_free_buffers(cb); 815*aa0a1e58SJeff Roberson err1: 816*aa0a1e58SJeff Roberson rping_free_qp(cb); 817*aa0a1e58SJeff Roberson err0: 818*aa0a1e58SJeff Roberson free_cb(cb); 819*aa0a1e58SJeff Roberson return NULL; 820*aa0a1e58SJeff Roberson } 821*aa0a1e58SJeff Roberson 822*aa0a1e58SJeff Roberson static int rping_run_persistent_server(struct rping_cb *listening_cb) 823*aa0a1e58SJeff Roberson { 824*aa0a1e58SJeff Roberson int ret; 825*aa0a1e58SJeff Roberson struct rping_cb *cb; 826*aa0a1e58SJeff Roberson 827*aa0a1e58SJeff Roberson ret = rping_bind_server(listening_cb); 828*aa0a1e58SJeff Roberson if (ret) 829*aa0a1e58SJeff Roberson return ret; 830*aa0a1e58SJeff Roberson 831*aa0a1e58SJeff Roberson while (1) { 832*aa0a1e58SJeff Roberson sem_wait(&listening_cb->sem); 833*aa0a1e58SJeff Roberson if (listening_cb->state != CONNECT_REQUEST) { 834*aa0a1e58SJeff Roberson fprintf(stderr, "wait for CONNECT_REQUEST state %d\n", 835*aa0a1e58SJeff Roberson listening_cb->state); 836*aa0a1e58SJeff Roberson return -1; 837*aa0a1e58SJeff Roberson } 838*aa0a1e58SJeff Roberson 839*aa0a1e58SJeff Roberson cb = clone_cb(listening_cb); 840*aa0a1e58SJeff Roberson if (!cb) 841*aa0a1e58SJeff Roberson return -1; 842*aa0a1e58SJeff Roberson pthread_create(&cb->persistent_server_thread, NULL, rping_persistent_server_thread, cb); 843*aa0a1e58SJeff Roberson } 844*aa0a1e58SJeff Roberson return 0; 845*aa0a1e58SJeff Roberson } 846*aa0a1e58SJeff Roberson 847*aa0a1e58SJeff Roberson static int rping_run_server(struct rping_cb *cb) 848*aa0a1e58SJeff Roberson { 849*aa0a1e58SJeff Roberson struct ibv_recv_wr *bad_wr; 850*aa0a1e58SJeff Roberson int ret; 851*aa0a1e58SJeff Roberson 852*aa0a1e58SJeff Roberson ret = rping_bind_server(cb); 853*aa0a1e58SJeff Roberson if (ret) 854*aa0a1e58SJeff Roberson return ret; 855*aa0a1e58SJeff Roberson 856*aa0a1e58SJeff Roberson sem_wait(&cb->sem); 857*aa0a1e58SJeff Roberson if (cb->state != CONNECT_REQUEST) { 858*aa0a1e58SJeff Roberson fprintf(stderr, "wait for CONNECT_REQUEST state %d\n", 859*aa0a1e58SJeff Roberson cb->state); 860*aa0a1e58SJeff Roberson return -1; 861*aa0a1e58SJeff Roberson } 862*aa0a1e58SJeff Roberson 863*aa0a1e58SJeff Roberson ret = rping_setup_qp(cb, cb->child_cm_id); 864*aa0a1e58SJeff Roberson if (ret) { 865*aa0a1e58SJeff Roberson fprintf(stderr, "setup_qp failed: %d\n", ret); 866*aa0a1e58SJeff Roberson return ret; 867*aa0a1e58SJeff Roberson } 868*aa0a1e58SJeff Roberson 869*aa0a1e58SJeff Roberson ret = rping_setup_buffers(cb); 870*aa0a1e58SJeff Roberson if (ret) { 871*aa0a1e58SJeff Roberson fprintf(stderr, "rping_setup_buffers failed: %d\n", ret); 872*aa0a1e58SJeff Roberson goto err1; 873*aa0a1e58SJeff Roberson } 874*aa0a1e58SJeff Roberson 875*aa0a1e58SJeff Roberson ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); 876*aa0a1e58SJeff Roberson if (ret) { 877*aa0a1e58SJeff Roberson fprintf(stderr, "ibv_post_recv failed: %d\n", ret); 878*aa0a1e58SJeff Roberson goto err2; 879*aa0a1e58SJeff Roberson } 880*aa0a1e58SJeff Roberson 881*aa0a1e58SJeff Roberson pthread_create(&cb->cqthread, NULL, cq_thread, cb); 882*aa0a1e58SJeff Roberson 883*aa0a1e58SJeff Roberson ret = rping_accept(cb); 884*aa0a1e58SJeff Roberson if (ret) { 885*aa0a1e58SJeff Roberson fprintf(stderr, "connect error %d\n", ret); 886*aa0a1e58SJeff Roberson goto err2; 887*aa0a1e58SJeff Roberson } 888*aa0a1e58SJeff Roberson 889*aa0a1e58SJeff Roberson rping_test_server(cb); 890*aa0a1e58SJeff Roberson rdma_disconnect(cb->child_cm_id); 891*aa0a1e58SJeff Roberson rdma_destroy_id(cb->child_cm_id); 892*aa0a1e58SJeff Roberson err2: 893*aa0a1e58SJeff Roberson rping_free_buffers(cb); 894*aa0a1e58SJeff Roberson err1: 895*aa0a1e58SJeff Roberson rping_free_qp(cb); 896*aa0a1e58SJeff Roberson 897*aa0a1e58SJeff Roberson return ret; 898*aa0a1e58SJeff Roberson } 899*aa0a1e58SJeff Roberson 900*aa0a1e58SJeff Roberson static int rping_test_client(struct rping_cb *cb) 901*aa0a1e58SJeff Roberson { 902*aa0a1e58SJeff Roberson int ping, start, cc, i, ret = 0; 903*aa0a1e58SJeff Roberson struct ibv_send_wr *bad_wr; 904*aa0a1e58SJeff Roberson unsigned char c; 905*aa0a1e58SJeff Roberson 906*aa0a1e58SJeff Roberson start = 65; 907*aa0a1e58SJeff Roberson for (ping = 0; !cb->count || ping < cb->count; ping++) { 908*aa0a1e58SJeff Roberson cb->state = RDMA_READ_ADV; 909*aa0a1e58SJeff Roberson 910*aa0a1e58SJeff Roberson /* Put some ascii text in the buffer. */ 911*aa0a1e58SJeff Roberson cc = sprintf(cb->start_buf, RPING_MSG_FMT, ping); 912*aa0a1e58SJeff Roberson for (i = cc, c = start; i < cb->size; i++) { 913*aa0a1e58SJeff Roberson cb->start_buf[i] = c; 914*aa0a1e58SJeff Roberson c++; 915*aa0a1e58SJeff Roberson if (c > 122) 916*aa0a1e58SJeff Roberson c = 65; 917*aa0a1e58SJeff Roberson } 918*aa0a1e58SJeff Roberson start++; 919*aa0a1e58SJeff Roberson if (start > 122) 920*aa0a1e58SJeff Roberson start = 65; 921*aa0a1e58SJeff Roberson cb->start_buf[cb->size - 1] = 0; 922*aa0a1e58SJeff Roberson 923*aa0a1e58SJeff Roberson rping_format_send(cb, cb->start_buf, cb->start_mr); 924*aa0a1e58SJeff Roberson ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); 925*aa0a1e58SJeff Roberson if (ret) { 926*aa0a1e58SJeff Roberson fprintf(stderr, "post send error %d\n", ret); 927*aa0a1e58SJeff Roberson break; 928*aa0a1e58SJeff Roberson } 929*aa0a1e58SJeff Roberson 930*aa0a1e58SJeff Roberson /* Wait for server to ACK */ 931*aa0a1e58SJeff Roberson sem_wait(&cb->sem); 932*aa0a1e58SJeff Roberson if (cb->state != RDMA_WRITE_ADV) { 933*aa0a1e58SJeff Roberson fprintf(stderr, "wait for RDMA_WRITE_ADV state %d\n", 934*aa0a1e58SJeff Roberson cb->state); 935*aa0a1e58SJeff Roberson ret = -1; 936*aa0a1e58SJeff Roberson break; 937*aa0a1e58SJeff Roberson } 938*aa0a1e58SJeff Roberson 939*aa0a1e58SJeff Roberson rping_format_send(cb, cb->rdma_buf, cb->rdma_mr); 940*aa0a1e58SJeff Roberson ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); 941*aa0a1e58SJeff Roberson if (ret) { 942*aa0a1e58SJeff Roberson fprintf(stderr, "post send error %d\n", ret); 943*aa0a1e58SJeff Roberson break; 944*aa0a1e58SJeff Roberson } 945*aa0a1e58SJeff Roberson 946*aa0a1e58SJeff Roberson /* Wait for the server to say the RDMA Write is complete. */ 947*aa0a1e58SJeff Roberson sem_wait(&cb->sem); 948*aa0a1e58SJeff Roberson if (cb->state != RDMA_WRITE_COMPLETE) { 949*aa0a1e58SJeff Roberson fprintf(stderr, "wait for RDMA_WRITE_COMPLETE state %d\n", 950*aa0a1e58SJeff Roberson cb->state); 951*aa0a1e58SJeff Roberson ret = -1; 952*aa0a1e58SJeff Roberson break; 953*aa0a1e58SJeff Roberson } 954*aa0a1e58SJeff Roberson 955*aa0a1e58SJeff Roberson if (cb->validate) 956*aa0a1e58SJeff Roberson if (memcmp(cb->start_buf, cb->rdma_buf, cb->size)) { 957*aa0a1e58SJeff Roberson fprintf(stderr, "data mismatch!\n"); 958*aa0a1e58SJeff Roberson ret = -1; 959*aa0a1e58SJeff Roberson break; 960*aa0a1e58SJeff Roberson } 961*aa0a1e58SJeff Roberson 962*aa0a1e58SJeff Roberson if (cb->verbose) 963*aa0a1e58SJeff Roberson printf("ping data: %s\n", cb->rdma_buf); 964*aa0a1e58SJeff Roberson } 965*aa0a1e58SJeff Roberson 966*aa0a1e58SJeff Roberson return ret; 967*aa0a1e58SJeff Roberson } 968*aa0a1e58SJeff Roberson 969*aa0a1e58SJeff Roberson static int rping_connect_client(struct rping_cb *cb) 970*aa0a1e58SJeff Roberson { 971*aa0a1e58SJeff Roberson struct rdma_conn_param conn_param; 972*aa0a1e58SJeff Roberson int ret; 973*aa0a1e58SJeff Roberson 974*aa0a1e58SJeff Roberson memset(&conn_param, 0, sizeof conn_param); 975*aa0a1e58SJeff Roberson conn_param.responder_resources = 1; 976*aa0a1e58SJeff Roberson conn_param.initiator_depth = 1; 977*aa0a1e58SJeff Roberson conn_param.retry_count = 10; 978*aa0a1e58SJeff Roberson 979*aa0a1e58SJeff Roberson ret = rdma_connect(cb->cm_id, &conn_param); 980*aa0a1e58SJeff Roberson if (ret) { 981*aa0a1e58SJeff Roberson perror("rdma_connect"); 982*aa0a1e58SJeff Roberson return ret; 983*aa0a1e58SJeff Roberson } 984*aa0a1e58SJeff Roberson 985*aa0a1e58SJeff Roberson sem_wait(&cb->sem); 986*aa0a1e58SJeff Roberson if (cb->state != CONNECTED) { 987*aa0a1e58SJeff Roberson fprintf(stderr, "wait for CONNECTED state %d\n", cb->state); 988*aa0a1e58SJeff Roberson return -1; 989*aa0a1e58SJeff Roberson } 990*aa0a1e58SJeff Roberson 991*aa0a1e58SJeff Roberson DEBUG_LOG("rmda_connect successful\n"); 992*aa0a1e58SJeff Roberson return 0; 993*aa0a1e58SJeff Roberson } 994*aa0a1e58SJeff Roberson 995*aa0a1e58SJeff Roberson static int rping_bind_client(struct rping_cb *cb) 996*aa0a1e58SJeff Roberson { 997*aa0a1e58SJeff Roberson int ret; 998*aa0a1e58SJeff Roberson 999*aa0a1e58SJeff Roberson if (cb->sin.ss_family == AF_INET) 1000*aa0a1e58SJeff Roberson ((struct sockaddr_in *) &cb->sin)->sin_port = cb->port; 1001*aa0a1e58SJeff Roberson else 1002*aa0a1e58SJeff Roberson ((struct sockaddr_in6 *) &cb->sin)->sin6_port = cb->port; 1003*aa0a1e58SJeff Roberson 1004*aa0a1e58SJeff Roberson ret = rdma_resolve_addr(cb->cm_id, NULL, (struct sockaddr *) &cb->sin, 2000); 1005*aa0a1e58SJeff Roberson if (ret) { 1006*aa0a1e58SJeff Roberson perror("rdma_resolve_addr"); 1007*aa0a1e58SJeff Roberson return ret; 1008*aa0a1e58SJeff Roberson } 1009*aa0a1e58SJeff Roberson 1010*aa0a1e58SJeff Roberson sem_wait(&cb->sem); 1011*aa0a1e58SJeff Roberson if (cb->state != ROUTE_RESOLVED) { 1012*aa0a1e58SJeff Roberson fprintf(stderr, "waiting for addr/route resolution state %d\n", 1013*aa0a1e58SJeff Roberson cb->state); 1014*aa0a1e58SJeff Roberson return -1; 1015*aa0a1e58SJeff Roberson } 1016*aa0a1e58SJeff Roberson 1017*aa0a1e58SJeff Roberson DEBUG_LOG("rdma_resolve_addr - rdma_resolve_route successful\n"); 1018*aa0a1e58SJeff Roberson return 0; 1019*aa0a1e58SJeff Roberson } 1020*aa0a1e58SJeff Roberson 1021*aa0a1e58SJeff Roberson static int rping_run_client(struct rping_cb *cb) 1022*aa0a1e58SJeff Roberson { 1023*aa0a1e58SJeff Roberson struct ibv_recv_wr *bad_wr; 1024*aa0a1e58SJeff Roberson int ret; 1025*aa0a1e58SJeff Roberson 1026*aa0a1e58SJeff Roberson ret = rping_bind_client(cb); 1027*aa0a1e58SJeff Roberson if (ret) 1028*aa0a1e58SJeff Roberson return ret; 1029*aa0a1e58SJeff Roberson 1030*aa0a1e58SJeff Roberson ret = rping_setup_qp(cb, cb->cm_id); 1031*aa0a1e58SJeff Roberson if (ret) { 1032*aa0a1e58SJeff Roberson fprintf(stderr, "setup_qp failed: %d\n", ret); 1033*aa0a1e58SJeff Roberson return ret; 1034*aa0a1e58SJeff Roberson } 1035*aa0a1e58SJeff Roberson 1036*aa0a1e58SJeff Roberson ret = rping_setup_buffers(cb); 1037*aa0a1e58SJeff Roberson if (ret) { 1038*aa0a1e58SJeff Roberson fprintf(stderr, "rping_setup_buffers failed: %d\n", ret); 1039*aa0a1e58SJeff Roberson goto err1; 1040*aa0a1e58SJeff Roberson } 1041*aa0a1e58SJeff Roberson 1042*aa0a1e58SJeff Roberson ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); 1043*aa0a1e58SJeff Roberson if (ret) { 1044*aa0a1e58SJeff Roberson fprintf(stderr, "ibv_post_recv failed: %d\n", ret); 1045*aa0a1e58SJeff Roberson goto err2; 1046*aa0a1e58SJeff Roberson } 1047*aa0a1e58SJeff Roberson 1048*aa0a1e58SJeff Roberson pthread_create(&cb->cqthread, NULL, cq_thread, cb); 1049*aa0a1e58SJeff Roberson 1050*aa0a1e58SJeff Roberson ret = rping_connect_client(cb); 1051*aa0a1e58SJeff Roberson if (ret) { 1052*aa0a1e58SJeff Roberson fprintf(stderr, "connect error %d\n", ret); 1053*aa0a1e58SJeff Roberson goto err2; 1054*aa0a1e58SJeff Roberson } 1055*aa0a1e58SJeff Roberson 1056*aa0a1e58SJeff Roberson rping_test_client(cb); 1057*aa0a1e58SJeff Roberson rdma_disconnect(cb->cm_id); 1058*aa0a1e58SJeff Roberson err2: 1059*aa0a1e58SJeff Roberson rping_free_buffers(cb); 1060*aa0a1e58SJeff Roberson err1: 1061*aa0a1e58SJeff Roberson rping_free_qp(cb); 1062*aa0a1e58SJeff Roberson 1063*aa0a1e58SJeff Roberson return ret; 1064*aa0a1e58SJeff Roberson } 1065*aa0a1e58SJeff Roberson 1066*aa0a1e58SJeff Roberson static int get_addr(char *dst, struct sockaddr *addr) 1067*aa0a1e58SJeff Roberson { 1068*aa0a1e58SJeff Roberson struct addrinfo *res; 1069*aa0a1e58SJeff Roberson int ret; 1070*aa0a1e58SJeff Roberson 1071*aa0a1e58SJeff Roberson ret = getaddrinfo(dst, NULL, NULL, &res); 1072*aa0a1e58SJeff Roberson if (ret) { 1073*aa0a1e58SJeff Roberson printf("getaddrinfo failed - invalid hostname or IP address\n"); 1074*aa0a1e58SJeff Roberson return ret; 1075*aa0a1e58SJeff Roberson } 1076*aa0a1e58SJeff Roberson 1077*aa0a1e58SJeff Roberson if (res->ai_family == PF_INET) 1078*aa0a1e58SJeff Roberson memcpy(addr, res->ai_addr, sizeof(struct sockaddr_in)); 1079*aa0a1e58SJeff Roberson else if (res->ai_family == PF_INET6) 1080*aa0a1e58SJeff Roberson memcpy(addr, res->ai_addr, sizeof(struct sockaddr_in6)); 1081*aa0a1e58SJeff Roberson else 1082*aa0a1e58SJeff Roberson ret = -1; 1083*aa0a1e58SJeff Roberson 1084*aa0a1e58SJeff Roberson freeaddrinfo(res); 1085*aa0a1e58SJeff Roberson return ret; 1086*aa0a1e58SJeff Roberson } 1087*aa0a1e58SJeff Roberson 1088*aa0a1e58SJeff Roberson static void usage(char *name) 1089*aa0a1e58SJeff Roberson { 1090*aa0a1e58SJeff Roberson printf("%s -s [-vVd] [-S size] [-C count] [-a addr] [-p port]\n", 1091*aa0a1e58SJeff Roberson name); 1092*aa0a1e58SJeff Roberson printf("%s -c [-vVd] [-S size] [-C count] -a addr [-p port]\n", 1093*aa0a1e58SJeff Roberson name); 1094*aa0a1e58SJeff Roberson printf("\t-c\t\tclient side\n"); 1095*aa0a1e58SJeff Roberson printf("\t-s\t\tserver side. To bind to any address with IPv6 use -a ::0\n"); 1096*aa0a1e58SJeff Roberson printf("\t-v\t\tdisplay ping data to stdout\n"); 1097*aa0a1e58SJeff Roberson printf("\t-V\t\tvalidate ping data\n"); 1098*aa0a1e58SJeff Roberson printf("\t-d\t\tdebug printfs\n"); 1099*aa0a1e58SJeff Roberson printf("\t-S size \tping data size\n"); 1100*aa0a1e58SJeff Roberson printf("\t-C count\tping count times\n"); 1101*aa0a1e58SJeff Roberson printf("\t-a addr\t\taddress\n"); 1102*aa0a1e58SJeff Roberson printf("\t-p port\t\tport\n"); 1103*aa0a1e58SJeff Roberson printf("\t-P\t\tpersistent server mode allowing multiple connections\n"); 1104*aa0a1e58SJeff Roberson } 1105*aa0a1e58SJeff Roberson 1106*aa0a1e58SJeff Roberson int main(int argc, char *argv[]) 1107*aa0a1e58SJeff Roberson { 1108*aa0a1e58SJeff Roberson struct rping_cb *cb; 1109*aa0a1e58SJeff Roberson int op; 1110*aa0a1e58SJeff Roberson int ret = 0; 1111*aa0a1e58SJeff Roberson int persistent_server = 0; 1112*aa0a1e58SJeff Roberson 1113*aa0a1e58SJeff Roberson cb = malloc(sizeof(*cb)); 1114*aa0a1e58SJeff Roberson if (!cb) 1115*aa0a1e58SJeff Roberson return -ENOMEM; 1116*aa0a1e58SJeff Roberson 1117*aa0a1e58SJeff Roberson memset(cb, 0, sizeof(*cb)); 1118*aa0a1e58SJeff Roberson cb->server = -1; 1119*aa0a1e58SJeff Roberson cb->state = IDLE; 1120*aa0a1e58SJeff Roberson cb->size = 64; 1121*aa0a1e58SJeff Roberson cb->sin.ss_family = PF_INET; 1122*aa0a1e58SJeff Roberson cb->port = htons(7174); 1123*aa0a1e58SJeff Roberson sem_init(&cb->sem, 0, 0); 1124*aa0a1e58SJeff Roberson 1125*aa0a1e58SJeff Roberson opterr = 0; 1126*aa0a1e58SJeff Roberson while ((op=getopt(argc, argv, "a:Pp:C:S:t:scvVd")) != -1) { 1127*aa0a1e58SJeff Roberson switch (op) { 1128*aa0a1e58SJeff Roberson case 'a': 1129*aa0a1e58SJeff Roberson ret = get_addr(optarg, (struct sockaddr *) &cb->sin); 1130*aa0a1e58SJeff Roberson break; 1131*aa0a1e58SJeff Roberson case 'P': 1132*aa0a1e58SJeff Roberson persistent_server = 1; 1133*aa0a1e58SJeff Roberson break; 1134*aa0a1e58SJeff Roberson case 'p': 1135*aa0a1e58SJeff Roberson cb->port = htons(atoi(optarg)); 1136*aa0a1e58SJeff Roberson DEBUG_LOG("port %d\n", (int) atoi(optarg)); 1137*aa0a1e58SJeff Roberson break; 1138*aa0a1e58SJeff Roberson case 's': 1139*aa0a1e58SJeff Roberson cb->server = 1; 1140*aa0a1e58SJeff Roberson DEBUG_LOG("server\n"); 1141*aa0a1e58SJeff Roberson break; 1142*aa0a1e58SJeff Roberson case 'c': 1143*aa0a1e58SJeff Roberson cb->server = 0; 1144*aa0a1e58SJeff Roberson DEBUG_LOG("client\n"); 1145*aa0a1e58SJeff Roberson break; 1146*aa0a1e58SJeff Roberson case 'S': 1147*aa0a1e58SJeff Roberson cb->size = atoi(optarg); 1148*aa0a1e58SJeff Roberson if ((cb->size < RPING_MIN_BUFSIZE) || 1149*aa0a1e58SJeff Roberson (cb->size > (RPING_BUFSIZE - 1))) { 1150*aa0a1e58SJeff Roberson fprintf(stderr, "Invalid size %d " 1151*aa0a1e58SJeff Roberson "(valid range is %Zd to %d)\n", 1152*aa0a1e58SJeff Roberson cb->size, RPING_MIN_BUFSIZE, RPING_BUFSIZE); 1153*aa0a1e58SJeff Roberson ret = EINVAL; 1154*aa0a1e58SJeff Roberson } else 1155*aa0a1e58SJeff Roberson DEBUG_LOG("size %d\n", (int) atoi(optarg)); 1156*aa0a1e58SJeff Roberson break; 1157*aa0a1e58SJeff Roberson case 'C': 1158*aa0a1e58SJeff Roberson cb->count = atoi(optarg); 1159*aa0a1e58SJeff Roberson if (cb->count < 0) { 1160*aa0a1e58SJeff Roberson fprintf(stderr, "Invalid count %d\n", 1161*aa0a1e58SJeff Roberson cb->count); 1162*aa0a1e58SJeff Roberson ret = EINVAL; 1163*aa0a1e58SJeff Roberson } else 1164*aa0a1e58SJeff Roberson DEBUG_LOG("count %d\n", (int) cb->count); 1165*aa0a1e58SJeff Roberson break; 1166*aa0a1e58SJeff Roberson case 'v': 1167*aa0a1e58SJeff Roberson cb->verbose++; 1168*aa0a1e58SJeff Roberson DEBUG_LOG("verbose\n"); 1169*aa0a1e58SJeff Roberson break; 1170*aa0a1e58SJeff Roberson case 'V': 1171*aa0a1e58SJeff Roberson cb->validate++; 1172*aa0a1e58SJeff Roberson DEBUG_LOG("validate data\n"); 1173*aa0a1e58SJeff Roberson break; 1174*aa0a1e58SJeff Roberson case 'd': 1175*aa0a1e58SJeff Roberson debug++; 1176*aa0a1e58SJeff Roberson break; 1177*aa0a1e58SJeff Roberson default: 1178*aa0a1e58SJeff Roberson usage("rping"); 1179*aa0a1e58SJeff Roberson ret = EINVAL; 1180*aa0a1e58SJeff Roberson goto out; 1181*aa0a1e58SJeff Roberson } 1182*aa0a1e58SJeff Roberson } 1183*aa0a1e58SJeff Roberson if (ret) 1184*aa0a1e58SJeff Roberson goto out; 1185*aa0a1e58SJeff Roberson 1186*aa0a1e58SJeff Roberson if (cb->server == -1) { 1187*aa0a1e58SJeff Roberson usage("rping"); 1188*aa0a1e58SJeff Roberson ret = EINVAL; 1189*aa0a1e58SJeff Roberson goto out; 1190*aa0a1e58SJeff Roberson } 1191*aa0a1e58SJeff Roberson 1192*aa0a1e58SJeff Roberson cb->cm_channel = rdma_create_event_channel(); 1193*aa0a1e58SJeff Roberson if (!cb->cm_channel) { 1194*aa0a1e58SJeff Roberson perror("rdma_create_event_channel"); 1195*aa0a1e58SJeff Roberson goto out; 1196*aa0a1e58SJeff Roberson } 1197*aa0a1e58SJeff Roberson 1198*aa0a1e58SJeff Roberson ret = rdma_create_id(cb->cm_channel, &cb->cm_id, cb, RDMA_PS_TCP); 1199*aa0a1e58SJeff Roberson if (ret) { 1200*aa0a1e58SJeff Roberson perror("rdma_create_id"); 1201*aa0a1e58SJeff Roberson goto out2; 1202*aa0a1e58SJeff Roberson } 1203*aa0a1e58SJeff Roberson DEBUG_LOG("created cm_id %p\n", cb->cm_id); 1204*aa0a1e58SJeff Roberson 1205*aa0a1e58SJeff Roberson pthread_create(&cb->cmthread, NULL, cm_thread, cb); 1206*aa0a1e58SJeff Roberson 1207*aa0a1e58SJeff Roberson if (cb->server) { 1208*aa0a1e58SJeff Roberson if (persistent_server) 1209*aa0a1e58SJeff Roberson ret = rping_run_persistent_server(cb); 1210*aa0a1e58SJeff Roberson else 1211*aa0a1e58SJeff Roberson ret = rping_run_server(cb); 1212*aa0a1e58SJeff Roberson } else 1213*aa0a1e58SJeff Roberson ret = rping_run_client(cb); 1214*aa0a1e58SJeff Roberson 1215*aa0a1e58SJeff Roberson DEBUG_LOG("destroy cm_id %p\n", cb->cm_id); 1216*aa0a1e58SJeff Roberson rdma_destroy_id(cb->cm_id); 1217*aa0a1e58SJeff Roberson out2: 1218*aa0a1e58SJeff Roberson rdma_destroy_event_channel(cb->cm_channel); 1219*aa0a1e58SJeff Roberson out: 1220*aa0a1e58SJeff Roberson free(cb); 1221*aa0a1e58SJeff Roberson return ret; 1222*aa0a1e58SJeff Roberson } 1223