xref: /freebsd/contrib/ofed/librdmacm/addrinfo.c (revision b51f459a2098622c31ed54f5c1bf0e03efce403b)
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 
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 
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 
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 
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 
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 
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 
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 
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