1/*
2 * Copyright (c) 2010 Intel Corporation.  All rights reserved.
3 *
4 * This software is available to you under the OpenIB.org BSD license
5 * below:
6 *
7 *     Redistribution and use in source and binary forms, with or
8 *     without modification, are permitted provided that the following
9 *     conditions are met:
10 *
11 *      - Redistributions of source code must retain the above
12 *        copyright notice, this list of conditions and the following
13 *        disclaimer.
14 *
15 *      - Redistributions in binary form must reproduce the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer in the documentation and/or other materials
18 *        provided with the distribution.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <netdb.h>
34#include <errno.h>
35#include <getopt.h>
36#include <rdma/rdma_cma.h>
37#include <rdma/rdma_verbs.h>
38
39static const char *server = "127.0.0.1";
40static const char *port = "7471";
41
42static struct rdma_cm_id *id;
43static struct ibv_mr *mr, *send_mr;
44static int send_flags;
45static uint8_t send_msg[16];
46static uint8_t recv_msg[16];
47
48static int run(void)
49{
50	struct rdma_addrinfo hints, *res;
51	struct ibv_qp_init_attr attr;
52	struct ibv_wc wc;
53	int ret;
54
55	memset(&hints, 0, sizeof hints);
56	hints.ai_port_space = RDMA_PS_TCP;
57	ret = rdma_getaddrinfo(server, port, &hints, &res);
58	if (ret) {
59		printf("rdma_getaddrinfo: %s\n", gai_strerror(ret));
60		goto out;
61	}
62
63	memset(&attr, 0, sizeof attr);
64	attr.cap.max_send_wr = attr.cap.max_recv_wr = 1;
65	attr.cap.max_send_sge = attr.cap.max_recv_sge = 1;
66	attr.cap.max_inline_data = 16;
67	attr.qp_context = id;
68	attr.sq_sig_all = 1;
69	ret = rdma_create_ep(&id, res, NULL, &attr);
70	// Check to see if we got inline data allowed or not
71	if (attr.cap.max_inline_data >= 16)
72		send_flags = IBV_SEND_INLINE;
73	else
74		printf("rdma_client: device doesn't support IBV_SEND_INLINE, "
75		       "using sge sends\n");
76
77	if (ret) {
78		perror("rdma_create_ep");
79		goto out_free_addrinfo;
80	}
81
82	mr = rdma_reg_msgs(id, recv_msg, 16);
83	if (!mr) {
84		perror("rdma_reg_msgs for recv_msg");
85		ret = -1;
86		goto out_destroy_ep;
87	}
88	if ((send_flags & IBV_SEND_INLINE) == 0) {
89		send_mr = rdma_reg_msgs(id, send_msg, 16);
90		if (!send_mr) {
91			perror("rdma_reg_msgs for send_msg");
92			ret = -1;
93			goto out_dereg_recv;
94		}
95	}
96
97	ret = rdma_post_recv(id, NULL, recv_msg, 16, mr);
98	if (ret) {
99		perror("rdma_post_recv");
100		goto out_dereg_send;
101	}
102
103	ret = rdma_connect(id, NULL);
104	if (ret) {
105		perror("rdma_connect");
106		goto out_dereg_send;
107	}
108
109	ret = rdma_post_send(id, NULL, send_msg, 16, send_mr, send_flags);
110	if (ret) {
111		perror("rdma_post_send");
112		goto out_disconnect;
113	}
114
115	while ((ret = rdma_get_send_comp(id, &wc)) == 0);
116	if (ret < 0) {
117		perror("rdma_get_send_comp");
118		goto out_disconnect;
119	}
120
121	while ((ret = rdma_get_recv_comp(id, &wc)) == 0);
122	if (ret < 0)
123		perror("rdma_get_recv_comp");
124	else
125		ret = 0;
126
127out_disconnect:
128	rdma_disconnect(id);
129out_dereg_send:
130	if ((send_flags & IBV_SEND_INLINE) == 0)
131		rdma_dereg_mr(send_mr);
132out_dereg_recv:
133	rdma_dereg_mr(mr);
134out_destroy_ep:
135	rdma_destroy_ep(id);
136out_free_addrinfo:
137	rdma_freeaddrinfo(res);
138out:
139	return ret;
140}
141
142int main(int argc, char **argv)
143{
144	int op, ret;
145
146	while ((op = getopt(argc, argv, "s:p:")) != -1) {
147		switch (op) {
148		case 's':
149			server = optarg;
150			break;
151		case 'p':
152			port = optarg;
153			break;
154		default:
155			printf("usage: %s\n", argv[0]);
156			printf("\t[-s server_address]\n");
157			printf("\t[-p port_number]\n");
158			exit(1);
159		}
160	}
161
162	printf("rdma_client: start\n");
163	ret = run();
164	printf("rdma_client: end %d\n", ret);
165	return ret;
166}
167