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