1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky * Copyright (c) 2013 Intel Corporation. All rights reserved.
3*d6b92ffaSHans Petter Selasky *
4*d6b92ffaSHans Petter Selasky * This software is available to you under the OpenIB.org BSD license
5*d6b92ffaSHans Petter Selasky * below:
6*d6b92ffaSHans Petter Selasky *
7*d6b92ffaSHans Petter Selasky * Redistribution and use in source and binary forms, with or
8*d6b92ffaSHans Petter Selasky * without modification, are permitted provided that the following
9*d6b92ffaSHans Petter Selasky * conditions are met:
10*d6b92ffaSHans Petter Selasky *
11*d6b92ffaSHans Petter Selasky * - Redistributions of source code must retain the above
12*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
13*d6b92ffaSHans Petter Selasky * disclaimer.
14*d6b92ffaSHans Petter Selasky *
15*d6b92ffaSHans Petter Selasky * - Redistributions in binary form must reproduce the above
16*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
17*d6b92ffaSHans Petter Selasky * disclaimer in the documentation and/or other materials
18*d6b92ffaSHans Petter Selasky * provided with the distribution.
19*d6b92ffaSHans Petter Selasky *
20*d6b92ffaSHans Petter Selasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21*d6b92ffaSHans Petter Selasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22*d6b92ffaSHans Petter Selasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
23*d6b92ffaSHans Petter Selasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24*d6b92ffaSHans Petter Selasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25*d6b92ffaSHans Petter Selasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26*d6b92ffaSHans Petter Selasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27*d6b92ffaSHans Petter Selasky * SOFTWARE.
28*d6b92ffaSHans Petter Selasky */
29*d6b92ffaSHans Petter Selasky
30*d6b92ffaSHans Petter Selasky #include <stdio.h>
31*d6b92ffaSHans Petter Selasky #include <stdlib.h>
32*d6b92ffaSHans Petter Selasky #include <string.h>
33*d6b92ffaSHans Petter Selasky #include <strings.h>
34*d6b92ffaSHans Petter Selasky #include <errno.h>
35*d6b92ffaSHans Petter Selasky #include <getopt.h>
36*d6b92ffaSHans Petter Selasky #include <sys/types.h>
37*d6b92ffaSHans Petter Selasky #include <sys/socket.h>
38*d6b92ffaSHans Petter Selasky #include <sys/time.h>
39*d6b92ffaSHans Petter Selasky #include <sys/wait.h>
40*d6b92ffaSHans Petter Selasky #include <netdb.h>
41*d6b92ffaSHans Petter Selasky #include <fcntl.h>
42*d6b92ffaSHans Petter Selasky #include <unistd.h>
43*d6b92ffaSHans Petter Selasky #include <netinet/tcp.h>
44*d6b92ffaSHans Petter Selasky
45*d6b92ffaSHans Petter Selasky #include <rdma/rdma_cma.h>
46*d6b92ffaSHans Petter Selasky #include "common.h"
47*d6b92ffaSHans Petter Selasky
48*d6b92ffaSHans Petter Selasky static struct rdma_addrinfo hints, *rai;
49*d6b92ffaSHans Petter Selasky static struct rdma_event_channel *channel;
50*d6b92ffaSHans Petter Selasky static const char *port = "7471";
51*d6b92ffaSHans Petter Selasky static char *dst_addr;
52*d6b92ffaSHans Petter Selasky static char *src_addr;
53*d6b92ffaSHans Petter Selasky static int timeout = 2000;
54*d6b92ffaSHans Petter Selasky static int retries = 2;
55*d6b92ffaSHans Petter Selasky
56*d6b92ffaSHans Petter Selasky enum step {
57*d6b92ffaSHans Petter Selasky STEP_CREATE_ID,
58*d6b92ffaSHans Petter Selasky STEP_BIND,
59*d6b92ffaSHans Petter Selasky STEP_RESOLVE_ADDR,
60*d6b92ffaSHans Petter Selasky STEP_RESOLVE_ROUTE,
61*d6b92ffaSHans Petter Selasky STEP_CREATE_QP,
62*d6b92ffaSHans Petter Selasky STEP_CONNECT,
63*d6b92ffaSHans Petter Selasky STEP_DISCONNECT,
64*d6b92ffaSHans Petter Selasky STEP_DESTROY,
65*d6b92ffaSHans Petter Selasky STEP_CNT
66*d6b92ffaSHans Petter Selasky };
67*d6b92ffaSHans Petter Selasky
68*d6b92ffaSHans Petter Selasky static const char *step_str[] = {
69*d6b92ffaSHans Petter Selasky "create id",
70*d6b92ffaSHans Petter Selasky "bind addr",
71*d6b92ffaSHans Petter Selasky "resolve addr",
72*d6b92ffaSHans Petter Selasky "resolve route",
73*d6b92ffaSHans Petter Selasky "create qp",
74*d6b92ffaSHans Petter Selasky "connect",
75*d6b92ffaSHans Petter Selasky "disconnect",
76*d6b92ffaSHans Petter Selasky "destroy"
77*d6b92ffaSHans Petter Selasky };
78*d6b92ffaSHans Petter Selasky
79*d6b92ffaSHans Petter Selasky struct node {
80*d6b92ffaSHans Petter Selasky struct rdma_cm_id *id;
81*d6b92ffaSHans Petter Selasky struct timeval times[STEP_CNT][2];
82*d6b92ffaSHans Petter Selasky int error;
83*d6b92ffaSHans Petter Selasky int retries;
84*d6b92ffaSHans Petter Selasky };
85*d6b92ffaSHans Petter Selasky
86*d6b92ffaSHans Petter Selasky struct list_head {
87*d6b92ffaSHans Petter Selasky struct list_head *prev;
88*d6b92ffaSHans Petter Selasky struct list_head *next;
89*d6b92ffaSHans Petter Selasky struct rdma_cm_id *id;
90*d6b92ffaSHans Petter Selasky };
91*d6b92ffaSHans Petter Selasky
92*d6b92ffaSHans Petter Selasky struct work_list {
93*d6b92ffaSHans Petter Selasky pthread_mutex_t lock;
94*d6b92ffaSHans Petter Selasky pthread_cond_t cond;
95*d6b92ffaSHans Petter Selasky struct list_head list;
96*d6b92ffaSHans Petter Selasky };
97*d6b92ffaSHans Petter Selasky
98*d6b92ffaSHans Petter Selasky #define INIT_LIST(x) ((x)->prev = (x)->next = (x))
99*d6b92ffaSHans Petter Selasky
100*d6b92ffaSHans Petter Selasky static struct work_list req_work;
101*d6b92ffaSHans Petter Selasky static struct work_list disc_work;
102*d6b92ffaSHans Petter Selasky static struct node *nodes;
103*d6b92ffaSHans Petter Selasky static struct timeval times[STEP_CNT][2];
104*d6b92ffaSHans Petter Selasky static int connections = 100;
105*d6b92ffaSHans Petter Selasky static volatile int started[STEP_CNT];
106*d6b92ffaSHans Petter Selasky static volatile int completed[STEP_CNT];
107*d6b92ffaSHans Petter Selasky static struct ibv_qp_init_attr init_qp_attr;
108*d6b92ffaSHans Petter Selasky static struct rdma_conn_param conn_param;
109*d6b92ffaSHans Petter Selasky
110*d6b92ffaSHans Petter Selasky #define start_perf(n, s) gettimeofday(&((n)->times[s][0]), NULL)
111*d6b92ffaSHans Petter Selasky #define end_perf(n, s) gettimeofday(&((n)->times[s][1]), NULL)
112*d6b92ffaSHans Petter Selasky #define start_time(s) gettimeofday(×[s][0], NULL)
113*d6b92ffaSHans Petter Selasky #define end_time(s) gettimeofday(×[s][1], NULL)
114*d6b92ffaSHans Petter Selasky
__list_delete(struct list_head * list)115*d6b92ffaSHans Petter Selasky static inline void __list_delete(struct list_head *list)
116*d6b92ffaSHans Petter Selasky {
117*d6b92ffaSHans Petter Selasky struct list_head *prev, *next;
118*d6b92ffaSHans Petter Selasky prev = list->prev;
119*d6b92ffaSHans Petter Selasky next = list->next;
120*d6b92ffaSHans Petter Selasky prev->next = next;
121*d6b92ffaSHans Petter Selasky next->prev = prev;
122*d6b92ffaSHans Petter Selasky INIT_LIST(list);
123*d6b92ffaSHans Petter Selasky }
124*d6b92ffaSHans Petter Selasky
__list_empty(struct work_list * list)125*d6b92ffaSHans Petter Selasky static inline int __list_empty(struct work_list *list)
126*d6b92ffaSHans Petter Selasky {
127*d6b92ffaSHans Petter Selasky return list->list.next == &list->list;
128*d6b92ffaSHans Petter Selasky }
129*d6b92ffaSHans Petter Selasky
__list_remove_head(struct work_list * work_list)130*d6b92ffaSHans Petter Selasky static inline struct list_head *__list_remove_head(struct work_list *work_list)
131*d6b92ffaSHans Petter Selasky {
132*d6b92ffaSHans Petter Selasky struct list_head *list_item;
133*d6b92ffaSHans Petter Selasky
134*d6b92ffaSHans Petter Selasky list_item = work_list->list.next;
135*d6b92ffaSHans Petter Selasky __list_delete(list_item);
136*d6b92ffaSHans Petter Selasky return list_item;
137*d6b92ffaSHans Petter Selasky }
138*d6b92ffaSHans Petter Selasky
list_add_tail(struct work_list * work_list,struct list_head * req)139*d6b92ffaSHans Petter Selasky static inline void list_add_tail(struct work_list *work_list, struct list_head *req)
140*d6b92ffaSHans Petter Selasky {
141*d6b92ffaSHans Petter Selasky int empty;
142*d6b92ffaSHans Petter Selasky pthread_mutex_lock(&work_list->lock);
143*d6b92ffaSHans Petter Selasky empty = __list_empty(work_list);
144*d6b92ffaSHans Petter Selasky req->prev = work_list->list.prev;
145*d6b92ffaSHans Petter Selasky req->next = &work_list->list;
146*d6b92ffaSHans Petter Selasky req->prev->next = work_list->list.prev = req;
147*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&work_list->lock);
148*d6b92ffaSHans Petter Selasky if (empty)
149*d6b92ffaSHans Petter Selasky pthread_cond_signal(&work_list->cond);
150*d6b92ffaSHans Petter Selasky }
151*d6b92ffaSHans Petter Selasky
zero_time(struct timeval * t)152*d6b92ffaSHans Petter Selasky static int zero_time(struct timeval *t)
153*d6b92ffaSHans Petter Selasky {
154*d6b92ffaSHans Petter Selasky return !(t->tv_sec || t->tv_usec);
155*d6b92ffaSHans Petter Selasky }
156*d6b92ffaSHans Petter Selasky
diff_us(struct timeval * end,struct timeval * start)157*d6b92ffaSHans Petter Selasky static float diff_us(struct timeval *end, struct timeval *start)
158*d6b92ffaSHans Petter Selasky {
159*d6b92ffaSHans Petter Selasky return (end->tv_sec - start->tv_sec) * 1000000. + (end->tv_usec - start->tv_usec);
160*d6b92ffaSHans Petter Selasky }
161*d6b92ffaSHans Petter Selasky
show_perf(void)162*d6b92ffaSHans Petter Selasky static void show_perf(void)
163*d6b92ffaSHans Petter Selasky {
164*d6b92ffaSHans Petter Selasky int c, i;
165*d6b92ffaSHans Petter Selasky float us, max[STEP_CNT], min[STEP_CNT];
166*d6b92ffaSHans Petter Selasky
167*d6b92ffaSHans Petter Selasky for (i = 0; i < STEP_CNT; i++) {
168*d6b92ffaSHans Petter Selasky max[i] = 0;
169*d6b92ffaSHans Petter Selasky min[i] = 999999999.;
170*d6b92ffaSHans Petter Selasky for (c = 0; c < connections; c++) {
171*d6b92ffaSHans Petter Selasky if (!zero_time(&nodes[c].times[i][0]) &&
172*d6b92ffaSHans Petter Selasky !zero_time(&nodes[c].times[i][1])) {
173*d6b92ffaSHans Petter Selasky us = diff_us(&nodes[c].times[i][1], &nodes[c].times[i][0]);
174*d6b92ffaSHans Petter Selasky if (us > max[i])
175*d6b92ffaSHans Petter Selasky max[i] = us;
176*d6b92ffaSHans Petter Selasky if (us < min[i])
177*d6b92ffaSHans Petter Selasky min[i] = us;
178*d6b92ffaSHans Petter Selasky }
179*d6b92ffaSHans Petter Selasky }
180*d6b92ffaSHans Petter Selasky }
181*d6b92ffaSHans Petter Selasky
182*d6b92ffaSHans Petter Selasky printf("step total ms max ms min us us / conn\n");
183*d6b92ffaSHans Petter Selasky for (i = 0; i < STEP_CNT; i++) {
184*d6b92ffaSHans Petter Selasky if (i == STEP_BIND && !src_addr)
185*d6b92ffaSHans Petter Selasky continue;
186*d6b92ffaSHans Petter Selasky
187*d6b92ffaSHans Petter Selasky us = diff_us(×[i][1], ×[i][0]);
188*d6b92ffaSHans Petter Selasky printf("%-13s: %11.2f%11.2f%11.2f%11.2f\n", step_str[i], us / 1000.,
189*d6b92ffaSHans Petter Selasky max[i] / 1000., min[i], us / connections);
190*d6b92ffaSHans Petter Selasky }
191*d6b92ffaSHans Petter Selasky }
192*d6b92ffaSHans Petter Selasky
addr_handler(struct node * n)193*d6b92ffaSHans Petter Selasky static void addr_handler(struct node *n)
194*d6b92ffaSHans Petter Selasky {
195*d6b92ffaSHans Petter Selasky end_perf(n, STEP_RESOLVE_ADDR);
196*d6b92ffaSHans Petter Selasky completed[STEP_RESOLVE_ADDR]++;
197*d6b92ffaSHans Petter Selasky }
198*d6b92ffaSHans Petter Selasky
route_handler(struct node * n)199*d6b92ffaSHans Petter Selasky static void route_handler(struct node *n)
200*d6b92ffaSHans Petter Selasky {
201*d6b92ffaSHans Petter Selasky end_perf(n, STEP_RESOLVE_ROUTE);
202*d6b92ffaSHans Petter Selasky completed[STEP_RESOLVE_ROUTE]++;
203*d6b92ffaSHans Petter Selasky }
204*d6b92ffaSHans Petter Selasky
conn_handler(struct node * n)205*d6b92ffaSHans Petter Selasky static void conn_handler(struct node *n)
206*d6b92ffaSHans Petter Selasky {
207*d6b92ffaSHans Petter Selasky end_perf(n, STEP_CONNECT);
208*d6b92ffaSHans Petter Selasky completed[STEP_CONNECT]++;
209*d6b92ffaSHans Petter Selasky }
210*d6b92ffaSHans Petter Selasky
disc_handler(struct node * n)211*d6b92ffaSHans Petter Selasky static void disc_handler(struct node *n)
212*d6b92ffaSHans Petter Selasky {
213*d6b92ffaSHans Petter Selasky end_perf(n, STEP_DISCONNECT);
214*d6b92ffaSHans Petter Selasky completed[STEP_DISCONNECT]++;
215*d6b92ffaSHans Petter Selasky }
216*d6b92ffaSHans Petter Selasky
__req_handler(struct rdma_cm_id * id)217*d6b92ffaSHans Petter Selasky static void __req_handler(struct rdma_cm_id *id)
218*d6b92ffaSHans Petter Selasky {
219*d6b92ffaSHans Petter Selasky int ret;
220*d6b92ffaSHans Petter Selasky
221*d6b92ffaSHans Petter Selasky ret = rdma_create_qp(id, NULL, &init_qp_attr);
222*d6b92ffaSHans Petter Selasky if (ret) {
223*d6b92ffaSHans Petter Selasky perror("failure creating qp");
224*d6b92ffaSHans Petter Selasky goto err;
225*d6b92ffaSHans Petter Selasky }
226*d6b92ffaSHans Petter Selasky
227*d6b92ffaSHans Petter Selasky ret = rdma_accept(id, NULL);
228*d6b92ffaSHans Petter Selasky if (ret) {
229*d6b92ffaSHans Petter Selasky perror("failure accepting");
230*d6b92ffaSHans Petter Selasky goto err;
231*d6b92ffaSHans Petter Selasky }
232*d6b92ffaSHans Petter Selasky return;
233*d6b92ffaSHans Petter Selasky
234*d6b92ffaSHans Petter Selasky err:
235*d6b92ffaSHans Petter Selasky printf("failing connection request\n");
236*d6b92ffaSHans Petter Selasky rdma_reject(id, NULL, 0);
237*d6b92ffaSHans Petter Selasky rdma_destroy_id(id);
238*d6b92ffaSHans Petter Selasky return;
239*d6b92ffaSHans Petter Selasky }
240*d6b92ffaSHans Petter Selasky
req_handler_thread(void * arg)241*d6b92ffaSHans Petter Selasky static void *req_handler_thread(void *arg)
242*d6b92ffaSHans Petter Selasky {
243*d6b92ffaSHans Petter Selasky struct list_head *work;
244*d6b92ffaSHans Petter Selasky do {
245*d6b92ffaSHans Petter Selasky pthread_mutex_lock(&req_work.lock);
246*d6b92ffaSHans Petter Selasky if (__list_empty(&req_work))
247*d6b92ffaSHans Petter Selasky pthread_cond_wait(&req_work.cond, &req_work.lock);
248*d6b92ffaSHans Petter Selasky work = __list_remove_head(&req_work);
249*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&req_work.lock);
250*d6b92ffaSHans Petter Selasky __req_handler(work->id);
251*d6b92ffaSHans Petter Selasky free(work);
252*d6b92ffaSHans Petter Selasky } while (1);
253*d6b92ffaSHans Petter Selasky return NULL;
254*d6b92ffaSHans Petter Selasky }
255*d6b92ffaSHans Petter Selasky
disc_handler_thread(void * arg)256*d6b92ffaSHans Petter Selasky static void *disc_handler_thread(void *arg)
257*d6b92ffaSHans Petter Selasky {
258*d6b92ffaSHans Petter Selasky struct list_head *work;
259*d6b92ffaSHans Petter Selasky do {
260*d6b92ffaSHans Petter Selasky pthread_mutex_lock(&disc_work.lock);
261*d6b92ffaSHans Petter Selasky if (__list_empty(&disc_work))
262*d6b92ffaSHans Petter Selasky pthread_cond_wait(&disc_work.cond, &disc_work.lock);
263*d6b92ffaSHans Petter Selasky work = __list_remove_head(&disc_work);
264*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&disc_work.lock);
265*d6b92ffaSHans Petter Selasky rdma_disconnect(work->id);
266*d6b92ffaSHans Petter Selasky rdma_destroy_id(work->id);
267*d6b92ffaSHans Petter Selasky free(work);
268*d6b92ffaSHans Petter Selasky } while (1);
269*d6b92ffaSHans Petter Selasky return NULL;
270*d6b92ffaSHans Petter Selasky }
271*d6b92ffaSHans Petter Selasky
cma_handler(struct rdma_cm_id * id,struct rdma_cm_event * event)272*d6b92ffaSHans Petter Selasky static void cma_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
273*d6b92ffaSHans Petter Selasky {
274*d6b92ffaSHans Petter Selasky struct node *n = id->context;
275*d6b92ffaSHans Petter Selasky struct list_head *request;
276*d6b92ffaSHans Petter Selasky
277*d6b92ffaSHans Petter Selasky switch (event->event) {
278*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_ADDR_RESOLVED:
279*d6b92ffaSHans Petter Selasky addr_handler(n);
280*d6b92ffaSHans Petter Selasky break;
281*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_ROUTE_RESOLVED:
282*d6b92ffaSHans Petter Selasky route_handler(n);
283*d6b92ffaSHans Petter Selasky break;
284*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_CONNECT_REQUEST:
285*d6b92ffaSHans Petter Selasky request = malloc(sizeof *request);
286*d6b92ffaSHans Petter Selasky if (!request) {
287*d6b92ffaSHans Petter Selasky perror("out of memory accepting connect request");
288*d6b92ffaSHans Petter Selasky rdma_reject(id, NULL, 0);
289*d6b92ffaSHans Petter Selasky rdma_destroy_id(id);
290*d6b92ffaSHans Petter Selasky } else {
291*d6b92ffaSHans Petter Selasky INIT_LIST(request);
292*d6b92ffaSHans Petter Selasky request->id = id;
293*d6b92ffaSHans Petter Selasky list_add_tail(&req_work, request);
294*d6b92ffaSHans Petter Selasky }
295*d6b92ffaSHans Petter Selasky break;
296*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_ESTABLISHED:
297*d6b92ffaSHans Petter Selasky if (n)
298*d6b92ffaSHans Petter Selasky conn_handler(n);
299*d6b92ffaSHans Petter Selasky break;
300*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_ADDR_ERROR:
301*d6b92ffaSHans Petter Selasky if (n->retries--) {
302*d6b92ffaSHans Petter Selasky if (!rdma_resolve_addr(n->id, rai->ai_src_addr,
303*d6b92ffaSHans Petter Selasky rai->ai_dst_addr, timeout))
304*d6b92ffaSHans Petter Selasky break;
305*d6b92ffaSHans Petter Selasky }
306*d6b92ffaSHans Petter Selasky printf("RDMA_CM_EVENT_ADDR_ERROR, error: %d\n", event->status);
307*d6b92ffaSHans Petter Selasky addr_handler(n);
308*d6b92ffaSHans Petter Selasky n->error = 1;
309*d6b92ffaSHans Petter Selasky break;
310*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_ROUTE_ERROR:
311*d6b92ffaSHans Petter Selasky if (n->retries--) {
312*d6b92ffaSHans Petter Selasky if (!rdma_resolve_route(n->id, timeout))
313*d6b92ffaSHans Petter Selasky break;
314*d6b92ffaSHans Petter Selasky }
315*d6b92ffaSHans Petter Selasky printf("RDMA_CM_EVENT_ROUTE_ERROR, error: %d\n", event->status);
316*d6b92ffaSHans Petter Selasky route_handler(n);
317*d6b92ffaSHans Petter Selasky n->error = 1;
318*d6b92ffaSHans Petter Selasky break;
319*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_CONNECT_ERROR:
320*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_UNREACHABLE:
321*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_REJECTED:
322*d6b92ffaSHans Petter Selasky printf("event: %s, error: %d\n",
323*d6b92ffaSHans Petter Selasky rdma_event_str(event->event), event->status);
324*d6b92ffaSHans Petter Selasky conn_handler(n);
325*d6b92ffaSHans Petter Selasky n->error = 1;
326*d6b92ffaSHans Petter Selasky break;
327*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_DISCONNECTED:
328*d6b92ffaSHans Petter Selasky if (!n) {
329*d6b92ffaSHans Petter Selasky request = malloc(sizeof *request);
330*d6b92ffaSHans Petter Selasky if (!request) {
331*d6b92ffaSHans Petter Selasky perror("out of memory queueing disconnect request, handling synchronously");
332*d6b92ffaSHans Petter Selasky rdma_disconnect(id);
333*d6b92ffaSHans Petter Selasky rdma_destroy_id(id);
334*d6b92ffaSHans Petter Selasky } else {
335*d6b92ffaSHans Petter Selasky INIT_LIST(request);
336*d6b92ffaSHans Petter Selasky request->id = id;
337*d6b92ffaSHans Petter Selasky list_add_tail(&disc_work, request);
338*d6b92ffaSHans Petter Selasky }
339*d6b92ffaSHans Petter Selasky } else
340*d6b92ffaSHans Petter Selasky disc_handler(n);
341*d6b92ffaSHans Petter Selasky break;
342*d6b92ffaSHans Petter Selasky case RDMA_CM_EVENT_DEVICE_REMOVAL:
343*d6b92ffaSHans Petter Selasky /* Cleanup will occur after test completes. */
344*d6b92ffaSHans Petter Selasky break;
345*d6b92ffaSHans Petter Selasky default:
346*d6b92ffaSHans Petter Selasky break;
347*d6b92ffaSHans Petter Selasky }
348*d6b92ffaSHans Petter Selasky rdma_ack_cm_event(event);
349*d6b92ffaSHans Petter Selasky }
350*d6b92ffaSHans Petter Selasky
alloc_nodes(void)351*d6b92ffaSHans Petter Selasky static int alloc_nodes(void)
352*d6b92ffaSHans Petter Selasky {
353*d6b92ffaSHans Petter Selasky int ret, i;
354*d6b92ffaSHans Petter Selasky
355*d6b92ffaSHans Petter Selasky nodes = calloc(sizeof *nodes, connections);
356*d6b92ffaSHans Petter Selasky if (!nodes)
357*d6b92ffaSHans Petter Selasky return -ENOMEM;
358*d6b92ffaSHans Petter Selasky
359*d6b92ffaSHans Petter Selasky printf("creating id\n");
360*d6b92ffaSHans Petter Selasky start_time(STEP_CREATE_ID);
361*d6b92ffaSHans Petter Selasky for (i = 0; i < connections; i++) {
362*d6b92ffaSHans Petter Selasky start_perf(&nodes[i], STEP_CREATE_ID);
363*d6b92ffaSHans Petter Selasky if (dst_addr) {
364*d6b92ffaSHans Petter Selasky ret = rdma_create_id(channel, &nodes[i].id, &nodes[i],
365*d6b92ffaSHans Petter Selasky hints.ai_port_space);
366*d6b92ffaSHans Petter Selasky if (ret)
367*d6b92ffaSHans Petter Selasky goto err;
368*d6b92ffaSHans Petter Selasky }
369*d6b92ffaSHans Petter Selasky end_perf(&nodes[i], STEP_CREATE_ID);
370*d6b92ffaSHans Petter Selasky }
371*d6b92ffaSHans Petter Selasky end_time(STEP_CREATE_ID);
372*d6b92ffaSHans Petter Selasky return 0;
373*d6b92ffaSHans Petter Selasky
374*d6b92ffaSHans Petter Selasky err:
375*d6b92ffaSHans Petter Selasky while (--i >= 0)
376*d6b92ffaSHans Petter Selasky rdma_destroy_id(nodes[i].id);
377*d6b92ffaSHans Petter Selasky free(nodes);
378*d6b92ffaSHans Petter Selasky return ret;
379*d6b92ffaSHans Petter Selasky }
380*d6b92ffaSHans Petter Selasky
cleanup_nodes(void)381*d6b92ffaSHans Petter Selasky static void cleanup_nodes(void)
382*d6b92ffaSHans Petter Selasky {
383*d6b92ffaSHans Petter Selasky int i;
384*d6b92ffaSHans Petter Selasky
385*d6b92ffaSHans Petter Selasky printf("destroying id\n");
386*d6b92ffaSHans Petter Selasky start_time(STEP_DESTROY);
387*d6b92ffaSHans Petter Selasky for (i = 0; i < connections; i++) {
388*d6b92ffaSHans Petter Selasky start_perf(&nodes[i], STEP_DESTROY);
389*d6b92ffaSHans Petter Selasky if (nodes[i].id)
390*d6b92ffaSHans Petter Selasky rdma_destroy_id(nodes[i].id);
391*d6b92ffaSHans Petter Selasky end_perf(&nodes[i], STEP_DESTROY);
392*d6b92ffaSHans Petter Selasky }
393*d6b92ffaSHans Petter Selasky end_time(STEP_DESTROY);
394*d6b92ffaSHans Petter Selasky }
395*d6b92ffaSHans Petter Selasky
process_events(void * arg)396*d6b92ffaSHans Petter Selasky static void *process_events(void *arg)
397*d6b92ffaSHans Petter Selasky {
398*d6b92ffaSHans Petter Selasky struct rdma_cm_event *event;
399*d6b92ffaSHans Petter Selasky int ret = 0;
400*d6b92ffaSHans Petter Selasky
401*d6b92ffaSHans Petter Selasky while (!ret) {
402*d6b92ffaSHans Petter Selasky ret = rdma_get_cm_event(channel, &event);
403*d6b92ffaSHans Petter Selasky if (!ret) {
404*d6b92ffaSHans Petter Selasky cma_handler(event->id, event);
405*d6b92ffaSHans Petter Selasky } else {
406*d6b92ffaSHans Petter Selasky perror("failure in rdma_get_cm_event in process_server_events");
407*d6b92ffaSHans Petter Selasky ret = errno;
408*d6b92ffaSHans Petter Selasky }
409*d6b92ffaSHans Petter Selasky }
410*d6b92ffaSHans Petter Selasky return NULL;
411*d6b92ffaSHans Petter Selasky }
412*d6b92ffaSHans Petter Selasky
run_server(void)413*d6b92ffaSHans Petter Selasky static int run_server(void)
414*d6b92ffaSHans Petter Selasky {
415*d6b92ffaSHans Petter Selasky pthread_t req_thread, disc_thread;
416*d6b92ffaSHans Petter Selasky struct rdma_cm_id *listen_id;
417*d6b92ffaSHans Petter Selasky int ret;
418*d6b92ffaSHans Petter Selasky
419*d6b92ffaSHans Petter Selasky INIT_LIST(&req_work.list);
420*d6b92ffaSHans Petter Selasky INIT_LIST(&disc_work.list);
421*d6b92ffaSHans Petter Selasky ret = pthread_mutex_init(&req_work.lock, NULL);
422*d6b92ffaSHans Petter Selasky if (ret) {
423*d6b92ffaSHans Petter Selasky perror("initializing mutex for req work");
424*d6b92ffaSHans Petter Selasky return ret;
425*d6b92ffaSHans Petter Selasky }
426*d6b92ffaSHans Petter Selasky
427*d6b92ffaSHans Petter Selasky ret = pthread_mutex_init(&disc_work.lock, NULL);
428*d6b92ffaSHans Petter Selasky if (ret) {
429*d6b92ffaSHans Petter Selasky perror("initializing mutex for disc work");
430*d6b92ffaSHans Petter Selasky return ret;
431*d6b92ffaSHans Petter Selasky }
432*d6b92ffaSHans Petter Selasky
433*d6b92ffaSHans Petter Selasky ret = pthread_cond_init(&req_work.cond, NULL);
434*d6b92ffaSHans Petter Selasky if (ret) {
435*d6b92ffaSHans Petter Selasky perror("initializing cond for req work");
436*d6b92ffaSHans Petter Selasky return ret;
437*d6b92ffaSHans Petter Selasky }
438*d6b92ffaSHans Petter Selasky
439*d6b92ffaSHans Petter Selasky ret = pthread_cond_init(&disc_work.cond, NULL);
440*d6b92ffaSHans Petter Selasky if (ret) {
441*d6b92ffaSHans Petter Selasky perror("initializing cond for disc work");
442*d6b92ffaSHans Petter Selasky return ret;
443*d6b92ffaSHans Petter Selasky }
444*d6b92ffaSHans Petter Selasky
445*d6b92ffaSHans Petter Selasky ret = pthread_create(&req_thread, NULL, req_handler_thread, NULL);
446*d6b92ffaSHans Petter Selasky if (ret) {
447*d6b92ffaSHans Petter Selasky perror("failed to create req handler thread");
448*d6b92ffaSHans Petter Selasky return ret;
449*d6b92ffaSHans Petter Selasky }
450*d6b92ffaSHans Petter Selasky
451*d6b92ffaSHans Petter Selasky ret = pthread_create(&disc_thread, NULL, disc_handler_thread, NULL);
452*d6b92ffaSHans Petter Selasky if (ret) {
453*d6b92ffaSHans Petter Selasky perror("failed to create disconnect handler thread");
454*d6b92ffaSHans Petter Selasky return ret;
455*d6b92ffaSHans Petter Selasky }
456*d6b92ffaSHans Petter Selasky
457*d6b92ffaSHans Petter Selasky ret = rdma_create_id(channel, &listen_id, NULL, hints.ai_port_space);
458*d6b92ffaSHans Petter Selasky if (ret) {
459*d6b92ffaSHans Petter Selasky perror("listen request failed");
460*d6b92ffaSHans Petter Selasky return ret;
461*d6b92ffaSHans Petter Selasky }
462*d6b92ffaSHans Petter Selasky
463*d6b92ffaSHans Petter Selasky ret = get_rdma_addr(src_addr, dst_addr, port, &hints, &rai);
464*d6b92ffaSHans Petter Selasky if (ret) {
465*d6b92ffaSHans Petter Selasky printf("getrdmaaddr error: %s\n", gai_strerror(ret));
466*d6b92ffaSHans Petter Selasky goto out;
467*d6b92ffaSHans Petter Selasky }
468*d6b92ffaSHans Petter Selasky
469*d6b92ffaSHans Petter Selasky ret = rdma_bind_addr(listen_id, rai->ai_src_addr);
470*d6b92ffaSHans Petter Selasky if (ret) {
471*d6b92ffaSHans Petter Selasky perror("bind address failed");
472*d6b92ffaSHans Petter Selasky goto out;
473*d6b92ffaSHans Petter Selasky }
474*d6b92ffaSHans Petter Selasky
475*d6b92ffaSHans Petter Selasky ret = rdma_listen(listen_id, 0);
476*d6b92ffaSHans Petter Selasky if (ret) {
477*d6b92ffaSHans Petter Selasky perror("failure trying to listen");
478*d6b92ffaSHans Petter Selasky goto out;
479*d6b92ffaSHans Petter Selasky }
480*d6b92ffaSHans Petter Selasky
481*d6b92ffaSHans Petter Selasky process_events(NULL);
482*d6b92ffaSHans Petter Selasky out:
483*d6b92ffaSHans Petter Selasky rdma_destroy_id(listen_id);
484*d6b92ffaSHans Petter Selasky return ret;
485*d6b92ffaSHans Petter Selasky }
486*d6b92ffaSHans Petter Selasky
run_client(void)487*d6b92ffaSHans Petter Selasky static int run_client(void)
488*d6b92ffaSHans Petter Selasky {
489*d6b92ffaSHans Petter Selasky pthread_t event_thread;
490*d6b92ffaSHans Petter Selasky int i, ret;
491*d6b92ffaSHans Petter Selasky
492*d6b92ffaSHans Petter Selasky ret = get_rdma_addr(src_addr, dst_addr, port, &hints, &rai);
493*d6b92ffaSHans Petter Selasky if (ret) {
494*d6b92ffaSHans Petter Selasky printf("getaddrinfo error: %s\n", gai_strerror(ret));
495*d6b92ffaSHans Petter Selasky return ret;
496*d6b92ffaSHans Petter Selasky }
497*d6b92ffaSHans Petter Selasky
498*d6b92ffaSHans Petter Selasky conn_param.responder_resources = 1;
499*d6b92ffaSHans Petter Selasky conn_param.initiator_depth = 1;
500*d6b92ffaSHans Petter Selasky conn_param.retry_count = retries;
501*d6b92ffaSHans Petter Selasky conn_param.private_data = rai->ai_connect;
502*d6b92ffaSHans Petter Selasky conn_param.private_data_len = rai->ai_connect_len;
503*d6b92ffaSHans Petter Selasky
504*d6b92ffaSHans Petter Selasky ret = pthread_create(&event_thread, NULL, process_events, NULL);
505*d6b92ffaSHans Petter Selasky if (ret) {
506*d6b92ffaSHans Petter Selasky perror("failure creating event thread");
507*d6b92ffaSHans Petter Selasky return ret;
508*d6b92ffaSHans Petter Selasky }
509*d6b92ffaSHans Petter Selasky
510*d6b92ffaSHans Petter Selasky if (src_addr) {
511*d6b92ffaSHans Petter Selasky printf("binding source address\n");
512*d6b92ffaSHans Petter Selasky start_time(STEP_BIND);
513*d6b92ffaSHans Petter Selasky for (i = 0; i < connections; i++) {
514*d6b92ffaSHans Petter Selasky start_perf(&nodes[i], STEP_BIND);
515*d6b92ffaSHans Petter Selasky ret = rdma_bind_addr(nodes[i].id, rai->ai_src_addr);
516*d6b92ffaSHans Petter Selasky if (ret) {
517*d6b92ffaSHans Petter Selasky perror("failure bind addr");
518*d6b92ffaSHans Petter Selasky nodes[i].error = 1;
519*d6b92ffaSHans Petter Selasky continue;
520*d6b92ffaSHans Petter Selasky }
521*d6b92ffaSHans Petter Selasky end_perf(&nodes[i], STEP_BIND);
522*d6b92ffaSHans Petter Selasky }
523*d6b92ffaSHans Petter Selasky end_time(STEP_BIND);
524*d6b92ffaSHans Petter Selasky }
525*d6b92ffaSHans Petter Selasky
526*d6b92ffaSHans Petter Selasky printf("resolving address\n");
527*d6b92ffaSHans Petter Selasky start_time(STEP_RESOLVE_ADDR);
528*d6b92ffaSHans Petter Selasky for (i = 0; i < connections; i++) {
529*d6b92ffaSHans Petter Selasky if (nodes[i].error)
530*d6b92ffaSHans Petter Selasky continue;
531*d6b92ffaSHans Petter Selasky nodes[i].retries = retries;
532*d6b92ffaSHans Petter Selasky start_perf(&nodes[i], STEP_RESOLVE_ADDR);
533*d6b92ffaSHans Petter Selasky ret = rdma_resolve_addr(nodes[i].id, rai->ai_src_addr,
534*d6b92ffaSHans Petter Selasky rai->ai_dst_addr, timeout);
535*d6b92ffaSHans Petter Selasky if (ret) {
536*d6b92ffaSHans Petter Selasky perror("failure getting addr");
537*d6b92ffaSHans Petter Selasky nodes[i].error = 1;
538*d6b92ffaSHans Petter Selasky continue;
539*d6b92ffaSHans Petter Selasky }
540*d6b92ffaSHans Petter Selasky started[STEP_RESOLVE_ADDR]++;
541*d6b92ffaSHans Petter Selasky }
542*d6b92ffaSHans Petter Selasky while (started[STEP_RESOLVE_ADDR] != completed[STEP_RESOLVE_ADDR]) sched_yield();
543*d6b92ffaSHans Petter Selasky end_time(STEP_RESOLVE_ADDR);
544*d6b92ffaSHans Petter Selasky
545*d6b92ffaSHans Petter Selasky printf("resolving route\n");
546*d6b92ffaSHans Petter Selasky start_time(STEP_RESOLVE_ROUTE);
547*d6b92ffaSHans Petter Selasky for (i = 0; i < connections; i++) {
548*d6b92ffaSHans Petter Selasky if (nodes[i].error)
549*d6b92ffaSHans Petter Selasky continue;
550*d6b92ffaSHans Petter Selasky nodes[i].retries = retries;
551*d6b92ffaSHans Petter Selasky start_perf(&nodes[i], STEP_RESOLVE_ROUTE);
552*d6b92ffaSHans Petter Selasky ret = rdma_resolve_route(nodes[i].id, timeout);
553*d6b92ffaSHans Petter Selasky if (ret) {
554*d6b92ffaSHans Petter Selasky perror("failure resolving route");
555*d6b92ffaSHans Petter Selasky nodes[i].error = 1;
556*d6b92ffaSHans Petter Selasky continue;
557*d6b92ffaSHans Petter Selasky }
558*d6b92ffaSHans Petter Selasky started[STEP_RESOLVE_ROUTE]++;
559*d6b92ffaSHans Petter Selasky }
560*d6b92ffaSHans Petter Selasky while (started[STEP_RESOLVE_ROUTE] != completed[STEP_RESOLVE_ROUTE]) sched_yield();
561*d6b92ffaSHans Petter Selasky end_time(STEP_RESOLVE_ROUTE);
562*d6b92ffaSHans Petter Selasky
563*d6b92ffaSHans Petter Selasky printf("creating qp\n");
564*d6b92ffaSHans Petter Selasky start_time(STEP_CREATE_QP);
565*d6b92ffaSHans Petter Selasky for (i = 0; i < connections; i++) {
566*d6b92ffaSHans Petter Selasky if (nodes[i].error)
567*d6b92ffaSHans Petter Selasky continue;
568*d6b92ffaSHans Petter Selasky start_perf(&nodes[i], STEP_CREATE_QP);
569*d6b92ffaSHans Petter Selasky ret = rdma_create_qp(nodes[i].id, NULL, &init_qp_attr);
570*d6b92ffaSHans Petter Selasky if (ret) {
571*d6b92ffaSHans Petter Selasky perror("failure creating qp");
572*d6b92ffaSHans Petter Selasky nodes[i].error = 1;
573*d6b92ffaSHans Petter Selasky continue;
574*d6b92ffaSHans Petter Selasky }
575*d6b92ffaSHans Petter Selasky end_perf(&nodes[i], STEP_CREATE_QP);
576*d6b92ffaSHans Petter Selasky }
577*d6b92ffaSHans Petter Selasky end_time(STEP_CREATE_QP);
578*d6b92ffaSHans Petter Selasky
579*d6b92ffaSHans Petter Selasky printf("connecting\n");
580*d6b92ffaSHans Petter Selasky start_time(STEP_CONNECT);
581*d6b92ffaSHans Petter Selasky for (i = 0; i < connections; i++) {
582*d6b92ffaSHans Petter Selasky if (nodes[i].error)
583*d6b92ffaSHans Petter Selasky continue;
584*d6b92ffaSHans Petter Selasky start_perf(&nodes[i], STEP_CONNECT);
585*d6b92ffaSHans Petter Selasky ret = rdma_connect(nodes[i].id, &conn_param);
586*d6b92ffaSHans Petter Selasky if (ret) {
587*d6b92ffaSHans Petter Selasky perror("failure rconnecting");
588*d6b92ffaSHans Petter Selasky nodes[i].error = 1;
589*d6b92ffaSHans Petter Selasky continue;
590*d6b92ffaSHans Petter Selasky }
591*d6b92ffaSHans Petter Selasky started[STEP_CONNECT]++;
592*d6b92ffaSHans Petter Selasky }
593*d6b92ffaSHans Petter Selasky while (started[STEP_CONNECT] != completed[STEP_CONNECT]) sched_yield();
594*d6b92ffaSHans Petter Selasky end_time(STEP_CONNECT);
595*d6b92ffaSHans Petter Selasky
596*d6b92ffaSHans Petter Selasky printf("disconnecting\n");
597*d6b92ffaSHans Petter Selasky start_time(STEP_DISCONNECT);
598*d6b92ffaSHans Petter Selasky for (i = 0; i < connections; i++) {
599*d6b92ffaSHans Petter Selasky if (nodes[i].error)
600*d6b92ffaSHans Petter Selasky continue;
601*d6b92ffaSHans Petter Selasky start_perf(&nodes[i], STEP_DISCONNECT);
602*d6b92ffaSHans Petter Selasky rdma_disconnect(nodes[i].id);
603*d6b92ffaSHans Petter Selasky started[STEP_DISCONNECT]++;
604*d6b92ffaSHans Petter Selasky }
605*d6b92ffaSHans Petter Selasky while (started[STEP_DISCONNECT] != completed[STEP_DISCONNECT]) sched_yield();
606*d6b92ffaSHans Petter Selasky end_time(STEP_DISCONNECT);
607*d6b92ffaSHans Petter Selasky
608*d6b92ffaSHans Petter Selasky return ret;
609*d6b92ffaSHans Petter Selasky }
610*d6b92ffaSHans Petter Selasky
main(int argc,char ** argv)611*d6b92ffaSHans Petter Selasky int main(int argc, char **argv)
612*d6b92ffaSHans Petter Selasky {
613*d6b92ffaSHans Petter Selasky int op, ret;
614*d6b92ffaSHans Petter Selasky
615*d6b92ffaSHans Petter Selasky hints.ai_port_space = RDMA_PS_TCP;
616*d6b92ffaSHans Petter Selasky hints.ai_qp_type = IBV_QPT_RC;
617*d6b92ffaSHans Petter Selasky while ((op = getopt(argc, argv, "s:b:c:p:r:t:")) != -1) {
618*d6b92ffaSHans Petter Selasky switch (op) {
619*d6b92ffaSHans Petter Selasky case 's':
620*d6b92ffaSHans Petter Selasky dst_addr = optarg;
621*d6b92ffaSHans Petter Selasky break;
622*d6b92ffaSHans Petter Selasky case 'b':
623*d6b92ffaSHans Petter Selasky src_addr = optarg;
624*d6b92ffaSHans Petter Selasky break;
625*d6b92ffaSHans Petter Selasky case 'c':
626*d6b92ffaSHans Petter Selasky connections = atoi(optarg);
627*d6b92ffaSHans Petter Selasky break;
628*d6b92ffaSHans Petter Selasky case 'p':
629*d6b92ffaSHans Petter Selasky port = optarg;
630*d6b92ffaSHans Petter Selasky break;
631*d6b92ffaSHans Petter Selasky case 'r':
632*d6b92ffaSHans Petter Selasky retries = atoi(optarg);
633*d6b92ffaSHans Petter Selasky break;
634*d6b92ffaSHans Petter Selasky case 't':
635*d6b92ffaSHans Petter Selasky timeout = atoi(optarg);
636*d6b92ffaSHans Petter Selasky break;
637*d6b92ffaSHans Petter Selasky default:
638*d6b92ffaSHans Petter Selasky printf("usage: %s\n", argv[0]);
639*d6b92ffaSHans Petter Selasky printf("\t[-s server_address]\n");
640*d6b92ffaSHans Petter Selasky printf("\t[-b bind_address]\n");
641*d6b92ffaSHans Petter Selasky printf("\t[-c connections]\n");
642*d6b92ffaSHans Petter Selasky printf("\t[-p port_number]\n");
643*d6b92ffaSHans Petter Selasky printf("\t[-r retries]\n");
644*d6b92ffaSHans Petter Selasky printf("\t[-t timeout_ms]\n");
645*d6b92ffaSHans Petter Selasky exit(1);
646*d6b92ffaSHans Petter Selasky }
647*d6b92ffaSHans Petter Selasky }
648*d6b92ffaSHans Petter Selasky
649*d6b92ffaSHans Petter Selasky init_qp_attr.cap.max_send_wr = 1;
650*d6b92ffaSHans Petter Selasky init_qp_attr.cap.max_recv_wr = 1;
651*d6b92ffaSHans Petter Selasky init_qp_attr.cap.max_send_sge = 1;
652*d6b92ffaSHans Petter Selasky init_qp_attr.cap.max_recv_sge = 1;
653*d6b92ffaSHans Petter Selasky init_qp_attr.qp_type = IBV_QPT_RC;
654*d6b92ffaSHans Petter Selasky
655*d6b92ffaSHans Petter Selasky channel = rdma_create_event_channel();
656*d6b92ffaSHans Petter Selasky if (!channel) {
657*d6b92ffaSHans Petter Selasky printf("failed to create event channel\n");
658*d6b92ffaSHans Petter Selasky exit(1);
659*d6b92ffaSHans Petter Selasky }
660*d6b92ffaSHans Petter Selasky
661*d6b92ffaSHans Petter Selasky if (dst_addr) {
662*d6b92ffaSHans Petter Selasky alloc_nodes();
663*d6b92ffaSHans Petter Selasky ret = run_client();
664*d6b92ffaSHans Petter Selasky } else {
665*d6b92ffaSHans Petter Selasky hints.ai_flags |= RAI_PASSIVE;
666*d6b92ffaSHans Petter Selasky ret = run_server();
667*d6b92ffaSHans Petter Selasky }
668*d6b92ffaSHans Petter Selasky
669*d6b92ffaSHans Petter Selasky cleanup_nodes();
670*d6b92ffaSHans Petter Selasky rdma_destroy_event_channel(channel);
671*d6b92ffaSHans Petter Selasky if (rai)
672*d6b92ffaSHans Petter Selasky rdma_freeaddrinfo(rai);
673*d6b92ffaSHans Petter Selasky
674*d6b92ffaSHans Petter Selasky show_perf();
675*d6b92ffaSHans Petter Selasky free(nodes);
676*d6b92ffaSHans Petter Selasky return ret;
677*d6b92ffaSHans Petter Selasky }
678