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