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