xref: /freebsd/contrib/ofed/librdmacm/examples/rping.c (revision 2a22df74e9fceaffd62ee437de08383d6cf8cfe0)
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