1 /*
2 * Copyright (c) 2010-2014 Intel Corporation. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 *
32 * $Id: cm.c 3453 2005-09-15 21:43:21Z sean.hefty $
33 */
34
35 #include <config.h>
36
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netdb.h>
40 #include <unistd.h>
41
42 #include "cma.h"
43 #include <rdma/rdma_cma.h>
44 #include <infiniband/ib.h>
45
46 static struct rdma_addrinfo nohints;
47
ucma_convert_to_ai(struct addrinfo * ai,const struct rdma_addrinfo * rai)48 static void ucma_convert_to_ai(struct addrinfo *ai,
49 const struct rdma_addrinfo *rai)
50 {
51 memset(ai, 0, sizeof(*ai));
52 if (rai->ai_flags & RAI_PASSIVE)
53 ai->ai_flags = AI_PASSIVE;
54 if (rai->ai_flags & RAI_NUMERICHOST)
55 ai->ai_flags |= AI_NUMERICHOST;
56 if (rai->ai_family != AF_IB)
57 ai->ai_family = rai->ai_family;
58
59 switch (rai->ai_qp_type) {
60 case IBV_QPT_RC:
61 case IBV_QPT_UC:
62 case IBV_QPT_XRC_SEND:
63 case IBV_QPT_XRC_RECV:
64 ai->ai_socktype = SOCK_STREAM;
65 break;
66 case IBV_QPT_UD:
67 ai->ai_socktype = SOCK_DGRAM;
68 break;
69 }
70
71 switch (rai->ai_port_space) {
72 case RDMA_PS_TCP:
73 ai->ai_protocol = IPPROTO_TCP;
74 break;
75 case RDMA_PS_IPOIB:
76 case RDMA_PS_UDP:
77 ai->ai_protocol = IPPROTO_UDP;
78 break;
79 case RDMA_PS_IB:
80 if (ai->ai_socktype == SOCK_STREAM)
81 ai->ai_protocol = IPPROTO_TCP;
82 else if (ai->ai_socktype == SOCK_DGRAM)
83 ai->ai_protocol = IPPROTO_UDP;
84 break;
85 }
86
87 if (rai->ai_flags & RAI_PASSIVE) {
88 ai->ai_addrlen = rai->ai_src_len;
89 ai->ai_addr = rai->ai_src_addr;
90 } else {
91 ai->ai_addrlen = rai->ai_dst_len;
92 ai->ai_addr = rai->ai_dst_addr;
93 }
94 ai->ai_canonname = rai->ai_dst_canonname;
95 ai->ai_next = NULL;
96 }
97
ucma_copy_addr(struct sockaddr ** dst,socklen_t * dst_len,struct sockaddr * src,socklen_t src_len)98 static int ucma_copy_addr(struct sockaddr **dst, socklen_t *dst_len,
99 struct sockaddr *src, socklen_t src_len)
100 {
101 *dst = malloc(src_len);
102 if (!(*dst))
103 return ERR(ENOMEM);
104
105 memcpy(*dst, src, src_len);
106 *dst_len = src_len;
107 return 0;
108 }
109
ucma_set_sid(enum rdma_port_space ps,struct sockaddr * addr,struct sockaddr_ib * sib)110 void ucma_set_sid(enum rdma_port_space ps, struct sockaddr *addr,
111 struct sockaddr_ib *sib)
112 {
113 __be16 port;
114
115 port = addr ? ucma_get_port(addr) : 0;
116 sib->sib_sid = htobe64(((uint64_t) ps << 16) + be16toh(port));
117
118 if (ps)
119 sib->sib_sid_mask = htobe64(RDMA_IB_IP_PS_MASK);
120 if (port)
121 sib->sib_sid_mask |= htobe64(RDMA_IB_IP_PORT_MASK);
122 }
123
ucma_convert_in6(int ps,struct sockaddr_ib ** dst,socklen_t * dst_len,struct sockaddr_in6 * src,socklen_t src_len)124 static int ucma_convert_in6(int ps, struct sockaddr_ib **dst, socklen_t *dst_len,
125 struct sockaddr_in6 *src, socklen_t src_len)
126 {
127 *dst = calloc(1, sizeof(struct sockaddr_ib));
128 if (!(*dst))
129 return ERR(ENOMEM);
130
131 (*dst)->sib_family = AF_IB;
132 (*dst)->sib_pkey = htobe16(0xFFFF);
133 (*dst)->sib_flowinfo = src->sin6_flowinfo;
134 ib_addr_set(&(*dst)->sib_addr, src->sin6_addr.s6_addr32[0],
135 src->sin6_addr.s6_addr32[1], src->sin6_addr.s6_addr32[2],
136 src->sin6_addr.s6_addr32[3]);
137 ucma_set_sid(ps, (struct sockaddr *) src, *dst);
138 (*dst)->sib_scope_id = src->sin6_scope_id;
139
140 *dst_len = sizeof(struct sockaddr_ib);
141 return 0;
142 }
143
ucma_convert_to_rai(struct rdma_addrinfo * rai,const struct rdma_addrinfo * hints,const struct addrinfo * ai)144 static int ucma_convert_to_rai(struct rdma_addrinfo *rai,
145 const struct rdma_addrinfo *hints,
146 const struct addrinfo *ai)
147 {
148 int ret;
149
150 if (hints->ai_qp_type) {
151 rai->ai_qp_type = hints->ai_qp_type;
152 } else {
153 switch (ai->ai_socktype) {
154 case SOCK_STREAM:
155 rai->ai_qp_type = IBV_QPT_RC;
156 break;
157 case SOCK_DGRAM:
158 rai->ai_qp_type = IBV_QPT_UD;
159 break;
160 }
161 }
162
163 if (hints->ai_port_space) {
164 rai->ai_port_space = hints->ai_port_space;
165 } else {
166 switch (ai->ai_protocol) {
167 case IPPROTO_TCP:
168 rai->ai_port_space = RDMA_PS_TCP;
169 break;
170 case IPPROTO_UDP:
171 rai->ai_port_space = RDMA_PS_UDP;
172 break;
173 }
174 }
175
176 if (ai->ai_flags & AI_PASSIVE) {
177 rai->ai_flags = RAI_PASSIVE;
178 if (ai->ai_canonname)
179 rai->ai_src_canonname = strdup(ai->ai_canonname);
180
181 if ((hints->ai_flags & RAI_FAMILY) && (hints->ai_family == AF_IB) &&
182 (hints->ai_flags & RAI_NUMERICHOST)) {
183 rai->ai_family = AF_IB;
184 ret = ucma_convert_in6(rai->ai_port_space,
185 (struct sockaddr_ib **) &rai->ai_src_addr,
186 &rai->ai_src_len,
187 (struct sockaddr_in6 *) ai->ai_addr,
188 ai->ai_addrlen);
189 } else {
190 rai->ai_family = ai->ai_family;
191 ret = ucma_copy_addr(&rai->ai_src_addr, &rai->ai_src_len,
192 ai->ai_addr, ai->ai_addrlen);
193 }
194 } else {
195 if (ai->ai_canonname)
196 rai->ai_dst_canonname = strdup(ai->ai_canonname);
197
198 if ((hints->ai_flags & RAI_FAMILY) && (hints->ai_family == AF_IB) &&
199 (hints->ai_flags & RAI_NUMERICHOST)) {
200 rai->ai_family = AF_IB;
201 ret = ucma_convert_in6(rai->ai_port_space,
202 (struct sockaddr_ib **) &rai->ai_dst_addr,
203 &rai->ai_dst_len,
204 (struct sockaddr_in6 *) ai->ai_addr,
205 ai->ai_addrlen);
206 } else {
207 rai->ai_family = ai->ai_family;
208 ret = ucma_copy_addr(&rai->ai_dst_addr, &rai->ai_dst_len,
209 ai->ai_addr, ai->ai_addrlen);
210 }
211 }
212 return ret;
213 }
214
ucma_getaddrinfo(const char * node,const char * service,const struct rdma_addrinfo * hints,struct rdma_addrinfo * rai)215 static int ucma_getaddrinfo(const char *node, const char *service,
216 const struct rdma_addrinfo *hints,
217 struct rdma_addrinfo *rai)
218 {
219 struct addrinfo ai_hints;
220 struct addrinfo *ai;
221 int ret;
222
223 if (hints != &nohints) {
224 ucma_convert_to_ai(&ai_hints, hints);
225 ret = getaddrinfo(node, service, &ai_hints, &ai);
226 } else {
227 ret = getaddrinfo(node, service, NULL, &ai);
228 }
229 if (ret)
230 return ret;
231
232 ret = ucma_convert_to_rai(rai, hints, ai);
233 freeaddrinfo(ai);
234 return ret;
235 }
236
rdma_getaddrinfo(const char * node,const char * service,const struct rdma_addrinfo * hints,struct rdma_addrinfo ** res)237 int rdma_getaddrinfo(const char *node, const char *service,
238 const struct rdma_addrinfo *hints,
239 struct rdma_addrinfo **res)
240 {
241 struct rdma_addrinfo *rai;
242 int ret;
243
244 if (!service && !node && !hints)
245 return ERR(EINVAL);
246
247 ret = ucma_init();
248 if (ret)
249 return ret;
250
251 rai = calloc(1, sizeof(*rai));
252 if (!rai)
253 return ERR(ENOMEM);
254
255 if (!hints)
256 hints = &nohints;
257
258 if (node || service) {
259 ret = ucma_getaddrinfo(node, service, hints, rai);
260 } else {
261 rai->ai_flags = hints->ai_flags;
262 rai->ai_family = hints->ai_family;
263 rai->ai_qp_type = hints->ai_qp_type;
264 rai->ai_port_space = hints->ai_port_space;
265 if (hints->ai_dst_len) {
266 ret = ucma_copy_addr(&rai->ai_dst_addr, &rai->ai_dst_len,
267 hints->ai_dst_addr, hints->ai_dst_len);
268 }
269 }
270 if (ret)
271 goto err;
272
273 if (!rai->ai_src_len && hints->ai_src_len) {
274 ret = ucma_copy_addr(&rai->ai_src_addr, &rai->ai_src_len,
275 hints->ai_src_addr, hints->ai_src_len);
276 if (ret)
277 goto err;
278 }
279
280 if (!(rai->ai_flags & RAI_PASSIVE))
281 ucma_ib_resolve(&rai, hints);
282
283 *res = rai;
284 return 0;
285
286 err:
287 rdma_freeaddrinfo(rai);
288 return ret;
289 }
290
rdma_freeaddrinfo(struct rdma_addrinfo * res)291 void rdma_freeaddrinfo(struct rdma_addrinfo *res)
292 {
293 struct rdma_addrinfo *rai;
294
295 while (res) {
296 rai = res;
297 res = res->ai_next;
298
299 if (rai->ai_connect)
300 free(rai->ai_connect);
301
302 if (rai->ai_route)
303 free(rai->ai_route);
304
305 if (rai->ai_src_canonname)
306 free(rai->ai_src_canonname);
307
308 if (rai->ai_dst_canonname)
309 free(rai->ai_dst_canonname);
310
311 if (rai->ai_src_addr)
312 free(rai->ai_src_addr);
313
314 if (rai->ai_dst_addr)
315 free(rai->ai_dst_addr);
316
317 free(rai);
318 }
319 }
320