]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/librdmacm/addrinfo.c
MFV r361936:
[FreeBSD/FreeBSD.git] / contrib / ofed / librdmacm / addrinfo.c
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 }