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 */
33d6b92ffaSHans Petter Selasky #define _GNU_SOURCE
34d6b92ffaSHans 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>
46d6b92ffaSHans 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,
82d6b92ffaSHans Petter Selasky DISCONNECTED,
83aa0a1e58SJeff Roberson ERROR
84aa0a1e58SJeff Roberson };
85aa0a1e58SJeff Roberson
86aa0a1e58SJeff Roberson struct rping_rdma_info {
87d6b92ffaSHans Petter Selasky __be64 buf;
88d6b92ffaSHans Petter Selasky __be32 rkey;
89d6b92ffaSHans 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;
145d6b92ffaSHans Petter Selasky struct sockaddr_storage ssource;
146d6b92ffaSHans 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
rping_cma_event_handler(struct rdma_cm_id * cma_id,struct rdma_cm_event * event)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");
219d6b92ffaSHans 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");
225d6b92ffaSHans Petter Selasky cb->state = ERROR;
226d6b92ffaSHans 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
server_recv(struct rping_cb * cb,struct ibv_wc * wc)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
246d6b92ffaSHans Petter Selasky cb->remote_rkey = be32toh(cb->recv_buf.rkey);
247d6b92ffaSHans Petter Selasky cb->remote_addr = be64toh(cb->recv_buf.buf);
248d6b92ffaSHans 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
client_recv(struct rping_cb * cb,struct ibv_wc * wc)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
rping_cq_event_handler(struct rping_cb * cb)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;
280d6b92ffaSHans 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) {
286d6b92ffaSHans Petter Selasky if (wc.status == IBV_WC_WR_FLUSH_ERR) {
287d6b92ffaSHans Petter Selasky flushed = 1;
288d6b92ffaSHans Petter Selasky continue;
289d6b92ffaSHans Petter Selasky
290d6b92ffaSHans Petter Selasky }
291d6b92ffaSHans Petter Selasky fprintf(stderr,
292d6b92ffaSHans 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 }
342d6b92ffaSHans 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
rping_accept(struct rping_cb * cb)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
356d6b92ffaSHans 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
rping_setup_wr(struct rping_cb * cb)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
rping_setup_buffers(struct rping_cb * cb)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
rping_free_buffers(struct rping_cb * cb)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
rping_create_qp(struct rping_cb * cb)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
rping_free_qp(struct rping_cb * cb)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
rping_setup_qp(struct rping_cb * cb,struct rdma_cm_id * cm_id)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
cm_thread(void * arg)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
cq_thread(void * arg)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
rping_format_send(struct rping_cb * cb,char * buf,struct ibv_mr * mr)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
623d6b92ffaSHans Petter Selasky info->buf = htobe64((uint64_t) (unsigned long) buf);
624d6b92ffaSHans Petter Selasky info->rkey = htobe32(mr->rkey);
625d6b92ffaSHans Petter Selasky info->size = htobe32(cb->size);
626aa0a1e58SJeff Roberson
627aa0a1e58SJeff Roberson DEBUG_LOG("RDMA addr %" PRIx64" rkey %x len %d\n",
628d6b92ffaSHans Petter Selasky be64toh(info->buf), be32toh(info->rkey), be32toh(info->size));
629aa0a1e58SJeff Roberson }
630aa0a1e58SJeff Roberson
rping_test_server(struct rping_cb * cb)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
728d6b92ffaSHans Petter Selasky return (cb->state == DISCONNECTED) ? 0 : ret;
729aa0a1e58SJeff Roberson }
730aa0a1e58SJeff Roberson
rping_bind_server(struct rping_cb * cb)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
clone_cb(struct rping_cb * listening_cb)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;
762d6b92ffaSHans 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
free_cb(struct rping_cb * cb)768aa0a1e58SJeff Roberson static void free_cb(struct rping_cb *cb)
769aa0a1e58SJeff Roberson {
770aa0a1e58SJeff Roberson free(cb);
771aa0a1e58SJeff Roberson }
772aa0a1e58SJeff Roberson
rping_persistent_server_thread(void * arg)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
797d6b92ffaSHans Petter Selasky ret = pthread_create(&cb->cqthread, NULL, cq_thread, cb);
798d6b92ffaSHans Petter Selasky if (ret) {
799d6b92ffaSHans Petter Selasky perror("pthread_create");
800d6b92ffaSHans Petter Selasky goto err2;
801d6b92ffaSHans 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
rping_run_persistent_server(struct rping_cb * listening_cb)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;
833d6b92ffaSHans 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
839d6b92ffaSHans Petter Selasky /*
840d6b92ffaSHans Petter Selasky * Set persistent server threads to DEATCHED state so
841d6b92ffaSHans Petter Selasky * they release all their resources when they exit.
842d6b92ffaSHans Petter Selasky */
843d6b92ffaSHans Petter Selasky ret = pthread_attr_init(&attr);
844d6b92ffaSHans Petter Selasky if (ret) {
845d6b92ffaSHans Petter Selasky perror("pthread_attr_init");
846d6b92ffaSHans Petter Selasky return ret;
847d6b92ffaSHans Petter Selasky }
848d6b92ffaSHans Petter Selasky ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
849d6b92ffaSHans Petter Selasky if (ret) {
850d6b92ffaSHans Petter Selasky perror("pthread_attr_setdetachstate");
851d6b92ffaSHans Petter Selasky return ret;
852d6b92ffaSHans Petter Selasky }
853d6b92ffaSHans 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;
865d6b92ffaSHans Petter Selasky
866d6b92ffaSHans Petter Selasky ret = pthread_create(&cb->persistent_server_thread, &attr, rping_persistent_server_thread, cb);
867d6b92ffaSHans Petter Selasky if (ret) {
868d6b92ffaSHans Petter Selasky perror("pthread_create");
869d6b92ffaSHans Petter Selasky return ret;
870d6b92ffaSHans Petter Selasky }
871aa0a1e58SJeff Roberson }
872aa0a1e58SJeff Roberson return 0;
873aa0a1e58SJeff Roberson }
874aa0a1e58SJeff Roberson
rping_run_server(struct rping_cb * cb)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
909d6b92ffaSHans Petter Selasky ret = pthread_create(&cb->cqthread, NULL, cq_thread, cb);
910d6b92ffaSHans Petter Selasky if (ret) {
911d6b92ffaSHans Petter Selasky perror("pthread_create");
912d6b92ffaSHans Petter Selasky goto err2;
913d6b92ffaSHans 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
921d6b92ffaSHans Petter Selasky ret = rping_test_server(cb);
922d6b92ffaSHans Petter Selasky if (ret) {
923d6b92ffaSHans Petter Selasky fprintf(stderr, "rping server failed: %d\n", ret);
924d6b92ffaSHans Petter Selasky goto err3;
925d6b92ffaSHans Petter Selasky }
926d6b92ffaSHans Petter Selasky
927d6b92ffaSHans Petter Selasky ret = 0;
928d6b92ffaSHans 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
rping_test_client(struct rping_cb * cb)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. */
951d6b92ffaSHans 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
1006d6b92ffaSHans Petter Selasky return (cb->state == DISCONNECTED) ? 0 : ret;
1007aa0a1e58SJeff Roberson }
1008aa0a1e58SJeff Roberson
rping_connect_client(struct rping_cb * cb)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;
1017d6b92ffaSHans 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
rping_bind_client(struct rping_cb * cb)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
1044d6b92ffaSHans Petter Selasky if (cb->ssource.ss_family)
1045d6b92ffaSHans Petter Selasky ret = rdma_resolve_addr(cb->cm_id, (struct sockaddr *) &cb->ssource,
1046d6b92ffaSHans Petter Selasky (struct sockaddr *) &cb->sin, 2000);
1047d6b92ffaSHans Petter Selasky else
1048aa0a1e58SJeff Roberson ret = rdma_resolve_addr(cb->cm_id, NULL, (struct sockaddr *) &cb->sin, 2000);
1049d6b92ffaSHans 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
rping_run_client(struct rping_cb * cb)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
1093d6b92ffaSHans Petter Selasky ret = pthread_create(&cb->cqthread, NULL, cq_thread, cb);
1094d6b92ffaSHans Petter Selasky if (ret) {
1095d6b92ffaSHans Petter Selasky perror("pthread_create");
1096d6b92ffaSHans Petter Selasky goto err2;
1097d6b92ffaSHans 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 }
1110d6b92ffaSHans 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
get_addr(char * dst,struct sockaddr * addr)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) {
1131d6b92ffaSHans 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
usage(const char * name)1146d6b92ffaSHans 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",
1149d6b92ffaSHans Petter Selasky basename(name));
1150d6b92ffaSHans Petter Selasky printf("%s -c [-vVd] [-S size] [-C count] [-I addr] -a addr [-p port]\n",
1151d6b92ffaSHans Petter Selasky basename(name));
1152aa0a1e58SJeff Roberson printf("\t-c\t\tclient side\n");
1153d6b92ffaSHans 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
main(int argc,char * argv[])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;
1180d6b92ffaSHans Petter Selasky cb->port = htobe16(7174);
1181aa0a1e58SJeff Roberson sem_init(&cb->sem, 0, 0);
1182aa0a1e58SJeff Roberson
1183*7815283dSNavdeep Parhar /* initialize sockaddr structure with defaults */
1184*7815283dSNavdeep Parhar ret = get_addr("0.0.0.0", (struct sockaddr *) &cb->sin);
1185*7815283dSNavdeep Parhar if (ret)
1186*7815283dSNavdeep Parhar goto out;
1187*7815283dSNavdeep Parhar
1188aa0a1e58SJeff Roberson opterr = 0;
1189d6b92ffaSHans Petter Selasky while ((op=getopt(argc, argv, "a:I:Pp:C:S:t:scvVd")) != -1) {
1190aa0a1e58SJeff Roberson switch (op) {
1191aa0a1e58SJeff Roberson case 'a':
1192aa0a1e58SJeff Roberson ret = get_addr(optarg, (struct sockaddr *) &cb->sin);
1193aa0a1e58SJeff Roberson break;
1194d6b92ffaSHans Petter Selasky case 'I':
1195d6b92ffaSHans Petter Selasky ret = get_addr(optarg, (struct sockaddr *) &cb->ssource);
1196d6b92ffaSHans Petter Selasky break;
1197aa0a1e58SJeff Roberson case 'P':
1198aa0a1e58SJeff Roberson persistent_server = 1;
1199aa0a1e58SJeff Roberson break;
1200aa0a1e58SJeff Roberson case 'p':
1201d6b92ffaSHans Petter Selasky cb->port = htobe16(atoi(optarg));
1202aa0a1e58SJeff Roberson DEBUG_LOG("port %d\n", (int) atoi(optarg));
1203aa0a1e58SJeff Roberson break;
1204aa0a1e58SJeff Roberson case 's':
1205aa0a1e58SJeff Roberson cb->server = 1;
1206aa0a1e58SJeff Roberson DEBUG_LOG("server\n");
1207aa0a1e58SJeff Roberson break;
1208aa0a1e58SJeff Roberson case 'c':
1209aa0a1e58SJeff Roberson cb->server = 0;
1210aa0a1e58SJeff Roberson DEBUG_LOG("client\n");
1211aa0a1e58SJeff Roberson break;
1212aa0a1e58SJeff Roberson case 'S':
1213aa0a1e58SJeff Roberson cb->size = atoi(optarg);
1214aa0a1e58SJeff Roberson if ((cb->size < RPING_MIN_BUFSIZE) ||
1215aa0a1e58SJeff Roberson (cb->size > (RPING_BUFSIZE - 1))) {
1216aa0a1e58SJeff Roberson fprintf(stderr, "Invalid size %d "
1217d6b92ffaSHans Petter Selasky "(valid range is %zd to %d)\n",
1218d6b92ffaSHans Petter Selasky cb->size, RPING_MIN_BUFSIZE, RPING_BUFSIZE);
1219aa0a1e58SJeff Roberson ret = EINVAL;
1220aa0a1e58SJeff Roberson } else
1221aa0a1e58SJeff Roberson DEBUG_LOG("size %d\n", (int) atoi(optarg));
1222aa0a1e58SJeff Roberson break;
1223aa0a1e58SJeff Roberson case 'C':
1224aa0a1e58SJeff Roberson cb->count = atoi(optarg);
1225aa0a1e58SJeff Roberson if (cb->count < 0) {
1226aa0a1e58SJeff Roberson fprintf(stderr, "Invalid count %d\n",
1227aa0a1e58SJeff Roberson cb->count);
1228aa0a1e58SJeff Roberson ret = EINVAL;
1229aa0a1e58SJeff Roberson } else
1230aa0a1e58SJeff Roberson DEBUG_LOG("count %d\n", (int) cb->count);
1231aa0a1e58SJeff Roberson break;
1232aa0a1e58SJeff Roberson case 'v':
1233aa0a1e58SJeff Roberson cb->verbose++;
1234aa0a1e58SJeff Roberson DEBUG_LOG("verbose\n");
1235aa0a1e58SJeff Roberson break;
1236aa0a1e58SJeff Roberson case 'V':
1237aa0a1e58SJeff Roberson cb->validate++;
1238aa0a1e58SJeff Roberson DEBUG_LOG("validate data\n");
1239aa0a1e58SJeff Roberson break;
1240aa0a1e58SJeff Roberson case 'd':
1241aa0a1e58SJeff Roberson debug++;
1242aa0a1e58SJeff Roberson break;
1243aa0a1e58SJeff Roberson default:
1244aa0a1e58SJeff Roberson usage("rping");
1245aa0a1e58SJeff Roberson ret = EINVAL;
1246aa0a1e58SJeff Roberson goto out;
1247aa0a1e58SJeff Roberson }
1248aa0a1e58SJeff Roberson }
1249aa0a1e58SJeff Roberson if (ret)
1250aa0a1e58SJeff Roberson goto out;
1251aa0a1e58SJeff Roberson
1252aa0a1e58SJeff Roberson if (cb->server == -1) {
1253aa0a1e58SJeff Roberson usage("rping");
1254aa0a1e58SJeff Roberson ret = EINVAL;
1255aa0a1e58SJeff Roberson goto out;
1256aa0a1e58SJeff Roberson }
1257aa0a1e58SJeff Roberson
1258aa0a1e58SJeff Roberson cb->cm_channel = rdma_create_event_channel();
1259aa0a1e58SJeff Roberson if (!cb->cm_channel) {
1260aa0a1e58SJeff Roberson perror("rdma_create_event_channel");
1261d6b92ffaSHans Petter Selasky ret = errno;
1262aa0a1e58SJeff Roberson goto out;
1263aa0a1e58SJeff Roberson }
1264aa0a1e58SJeff Roberson
1265aa0a1e58SJeff Roberson ret = rdma_create_id(cb->cm_channel, &cb->cm_id, cb, RDMA_PS_TCP);
1266aa0a1e58SJeff Roberson if (ret) {
1267aa0a1e58SJeff Roberson perror("rdma_create_id");
1268aa0a1e58SJeff Roberson goto out2;
1269aa0a1e58SJeff Roberson }
1270aa0a1e58SJeff Roberson DEBUG_LOG("created cm_id %p\n", cb->cm_id);
1271aa0a1e58SJeff Roberson
1272d6b92ffaSHans Petter Selasky ret = pthread_create(&cb->cmthread, NULL, cm_thread, cb);
1273d6b92ffaSHans Petter Selasky if (ret) {
1274d6b92ffaSHans Petter Selasky perror("pthread_create");
1275d6b92ffaSHans Petter Selasky goto out2;
1276d6b92ffaSHans Petter Selasky }
1277aa0a1e58SJeff Roberson
1278aa0a1e58SJeff Roberson if (cb->server) {
1279aa0a1e58SJeff Roberson if (persistent_server)
1280aa0a1e58SJeff Roberson ret = rping_run_persistent_server(cb);
1281aa0a1e58SJeff Roberson else
1282aa0a1e58SJeff Roberson ret = rping_run_server(cb);
1283d6b92ffaSHans Petter Selasky } else {
1284aa0a1e58SJeff Roberson ret = rping_run_client(cb);
1285d6b92ffaSHans Petter Selasky }
1286aa0a1e58SJeff Roberson
1287aa0a1e58SJeff Roberson DEBUG_LOG("destroy cm_id %p\n", cb->cm_id);
1288aa0a1e58SJeff Roberson rdma_destroy_id(cb->cm_id);
1289aa0a1e58SJeff Roberson out2:
1290aa0a1e58SJeff Roberson rdma_destroy_event_channel(cb->cm_channel);
1291aa0a1e58SJeff Roberson out:
1292aa0a1e58SJeff Roberson free(cb);
1293aa0a1e58SJeff Roberson return ret;
1294aa0a1e58SJeff Roberson }
1295