addrinfo.c revision 331769
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
46static struct rdma_addrinfo nohints;
47
48static 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
98static 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
110void 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
124static 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
144static 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
215static 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
237int 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
286err:
287	rdma_freeaddrinfo(rai);
288	return ret;
289}
290
291void 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