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