1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk/log.h" 37 #include "spdk/sock.h" 38 #include "spdk_internal/sock.h" 39 #include "spdk/queue.h" 40 41 static STAILQ_HEAD(, spdk_net_impl) g_net_impls = STAILQ_HEAD_INITIALIZER(g_net_impls); 42 43 struct spdk_sock_placement_id_entry { 44 int placement_id; 45 uint32_t ref; 46 struct spdk_sock_group *group; 47 STAILQ_ENTRY(spdk_sock_placement_id_entry) link; 48 }; 49 50 static STAILQ_HEAD(, spdk_sock_placement_id_entry) g_placement_id_map = STAILQ_HEAD_INITIALIZER( 51 g_placement_id_map); 52 static pthread_mutex_t g_map_table_mutex = PTHREAD_MUTEX_INITIALIZER; 53 54 /* Insert a group into the placement map. 55 * If the group is already in the map, take a reference. 56 */ 57 static int 58 spdk_sock_map_insert(int placement_id, struct spdk_sock_group *group) 59 { 60 struct spdk_sock_placement_id_entry *entry; 61 62 pthread_mutex_lock(&g_map_table_mutex); 63 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 64 if (placement_id == entry->placement_id) { 65 /* The mapping already exists, it means that different sockets have 66 * the same placement_ids. 67 */ 68 entry->ref++; 69 pthread_mutex_unlock(&g_map_table_mutex); 70 return 0; 71 } 72 } 73 74 entry = calloc(1, sizeof(*entry)); 75 if (!entry) { 76 SPDK_ERRLOG("Cannot allocate an entry for placement_id=%u\n", placement_id); 77 pthread_mutex_unlock(&g_map_table_mutex); 78 return -ENOMEM; 79 } 80 81 entry->placement_id = placement_id; 82 entry->group = group; 83 entry->ref++; 84 85 STAILQ_INSERT_TAIL(&g_placement_id_map, entry, link); 86 pthread_mutex_unlock(&g_map_table_mutex); 87 88 return 0; 89 } 90 91 /* Release a reference to the group for a given placement_id. 92 * If the reference count is 0, remove the group. 93 */ 94 static void 95 spdk_sock_map_release(int placement_id) 96 { 97 struct spdk_sock_placement_id_entry *entry; 98 99 pthread_mutex_lock(&g_map_table_mutex); 100 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 101 if (placement_id == entry->placement_id) { 102 assert(entry->ref > 0); 103 entry->ref--; 104 if (!entry->ref) { 105 STAILQ_REMOVE(&g_placement_id_map, entry, spdk_sock_placement_id_entry, link); 106 free(entry); 107 } 108 break; 109 } 110 } 111 112 pthread_mutex_unlock(&g_map_table_mutex); 113 } 114 115 /* Look up the group for a placement_id. */ 116 static void 117 spdk_sock_map_lookup(int placement_id, struct spdk_sock_group **group) 118 { 119 struct spdk_sock_placement_id_entry *entry; 120 121 *group = NULL; 122 pthread_mutex_lock(&g_map_table_mutex); 123 STAILQ_FOREACH(entry, &g_placement_id_map, link) { 124 if (placement_id == entry->placement_id) { 125 assert(entry->group != NULL); 126 *group = entry->group; 127 break; 128 } 129 } 130 pthread_mutex_unlock(&g_map_table_mutex); 131 } 132 133 /* Remove the socket group from the map table */ 134 static void 135 spdk_sock_remove_sock_group_from_map_table(struct spdk_sock_group *group) 136 { 137 struct spdk_sock_placement_id_entry *entry, *tmp; 138 139 pthread_mutex_lock(&g_map_table_mutex); 140 STAILQ_FOREACH_SAFE(entry, &g_placement_id_map, link, tmp) { 141 if (entry->group == group) { 142 STAILQ_REMOVE(&g_placement_id_map, entry, spdk_sock_placement_id_entry, link); 143 free(entry); 144 } 145 } 146 pthread_mutex_unlock(&g_map_table_mutex); 147 148 } 149 150 int 151 spdk_sock_get_optimal_sock_group(struct spdk_sock *sock, struct spdk_sock_group **group) 152 { 153 int placement_id = 0, rc; 154 155 rc = sock->net_impl->get_placement_id(sock, &placement_id); 156 if (!rc && (placement_id != 0)) { 157 spdk_sock_map_lookup(placement_id, group); 158 return 0; 159 } else { 160 return -1; 161 } 162 } 163 164 int 165 spdk_sock_getaddr(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, 166 char *caddr, int clen, uint16_t *cport) 167 { 168 return sock->net_impl->getaddr(sock, saddr, slen, sport, caddr, clen, cport); 169 } 170 171 struct spdk_sock * 172 spdk_sock_connect(const char *ip, int port) 173 { 174 struct spdk_net_impl *impl = NULL; 175 struct spdk_sock *sock; 176 177 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 178 sock = impl->connect(ip, port); 179 if (sock != NULL) { 180 sock->net_impl = impl; 181 return sock; 182 } 183 } 184 185 return NULL; 186 } 187 188 struct spdk_sock * 189 spdk_sock_listen(const char *ip, int port) 190 { 191 struct spdk_net_impl *impl = NULL; 192 struct spdk_sock *sock; 193 194 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 195 sock = impl->listen(ip, port); 196 if (sock != NULL) { 197 sock->net_impl = impl; 198 return sock; 199 } 200 } 201 202 return NULL; 203 } 204 205 struct spdk_sock * 206 spdk_sock_accept(struct spdk_sock *sock) 207 { 208 struct spdk_sock *new_sock; 209 210 new_sock = sock->net_impl->accept(sock); 211 if (new_sock != NULL) { 212 new_sock->net_impl = sock->net_impl; 213 } 214 215 return new_sock; 216 } 217 218 int 219 spdk_sock_close(struct spdk_sock **sock) 220 { 221 int rc; 222 223 if (*sock == NULL) { 224 errno = EBADF; 225 return -1; 226 } 227 228 if ((*sock)->cb_fn != NULL) { 229 /* This sock is still part of a sock_group. */ 230 errno = EBUSY; 231 return -1; 232 } 233 234 rc = (*sock)->net_impl->close(*sock); 235 if (rc == 0) { 236 *sock = NULL; 237 } 238 239 return rc; 240 } 241 242 ssize_t 243 spdk_sock_recv(struct spdk_sock *sock, void *buf, size_t len) 244 { 245 if (sock == NULL) { 246 errno = EBADF; 247 return -1; 248 } 249 250 return sock->net_impl->recv(sock, buf, len); 251 } 252 253 ssize_t 254 spdk_sock_readv(struct spdk_sock *sock, struct iovec *iov, int iovcnt) 255 { 256 if (sock == NULL) { 257 errno = EBADF; 258 return -1; 259 } 260 261 return sock->net_impl->readv(sock, iov, iovcnt); 262 } 263 264 ssize_t 265 spdk_sock_writev(struct spdk_sock *sock, struct iovec *iov, int iovcnt) 266 { 267 if (sock == NULL) { 268 errno = EBADF; 269 return -1; 270 } 271 272 return sock->net_impl->writev(sock, iov, iovcnt); 273 } 274 275 int 276 spdk_sock_set_recvlowat(struct spdk_sock *sock, int nbytes) 277 { 278 return sock->net_impl->set_recvlowat(sock, nbytes); 279 } 280 281 int 282 spdk_sock_set_recvbuf(struct spdk_sock *sock, int sz) 283 { 284 return sock->net_impl->set_recvbuf(sock, sz); 285 } 286 287 int 288 spdk_sock_set_sendbuf(struct spdk_sock *sock, int sz) 289 { 290 return sock->net_impl->set_sendbuf(sock, sz); 291 } 292 293 int 294 spdk_sock_set_priority(struct spdk_sock *sock, int priority) 295 { 296 return sock->net_impl->set_priority(sock, priority); 297 } 298 299 bool 300 spdk_sock_is_ipv6(struct spdk_sock *sock) 301 { 302 return sock->net_impl->is_ipv6(sock); 303 } 304 305 bool 306 spdk_sock_is_ipv4(struct spdk_sock *sock) 307 { 308 return sock->net_impl->is_ipv4(sock); 309 } 310 311 struct spdk_sock_group * 312 spdk_sock_group_create(void *ctx) 313 { 314 struct spdk_net_impl *impl = NULL; 315 struct spdk_sock_group *group; 316 struct spdk_sock_group_impl *group_impl; 317 318 group = calloc(1, sizeof(*group)); 319 if (group == NULL) { 320 return NULL; 321 } 322 323 STAILQ_INIT(&group->group_impls); 324 325 STAILQ_FOREACH_FROM(impl, &g_net_impls, link) { 326 group_impl = impl->group_impl_create(); 327 if (group_impl != NULL) { 328 STAILQ_INSERT_TAIL(&group->group_impls, group_impl, link); 329 TAILQ_INIT(&group_impl->socks); 330 group_impl->net_impl = impl; 331 } 332 } 333 334 group->ctx = ctx; 335 return group; 336 } 337 338 void * 339 spdk_sock_group_get_ctx(struct spdk_sock_group *group) 340 { 341 if (group == NULL) { 342 return NULL; 343 } 344 345 return group->ctx; 346 } 347 348 int 349 spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock, 350 spdk_sock_cb cb_fn, void *cb_arg) 351 { 352 struct spdk_sock_group_impl *group_impl = NULL; 353 int rc, placement_id = 0; 354 355 if (cb_fn == NULL) { 356 errno = EINVAL; 357 return -1; 358 } 359 360 if (sock->cb_fn != NULL) { 361 /* 362 * This sock is already part of a sock_group. Currently we don't 363 * support this. 364 */ 365 errno = EBUSY; 366 return -1; 367 } 368 369 rc = sock->net_impl->get_placement_id(sock, &placement_id); 370 if (!rc && (placement_id != 0)) { 371 rc = spdk_sock_map_insert(placement_id, group); 372 if (rc < 0) { 373 return -1; 374 } 375 } 376 377 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 378 if (sock->net_impl == group_impl->net_impl) { 379 break; 380 } 381 } 382 383 if (group_impl == NULL) { 384 errno = EINVAL; 385 return -1; 386 } 387 388 rc = group_impl->net_impl->group_impl_add_sock(group_impl, sock); 389 if (rc == 0) { 390 TAILQ_INSERT_TAIL(&group_impl->socks, sock, link); 391 sock->cb_fn = cb_fn; 392 sock->cb_arg = cb_arg; 393 } 394 395 return rc; 396 } 397 398 int 399 spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock) 400 { 401 struct spdk_sock_group_impl *group_impl = NULL; 402 int rc, placement_id = 0; 403 404 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 405 if (sock->net_impl == group_impl->net_impl) { 406 break; 407 } 408 } 409 410 if (group_impl == NULL) { 411 errno = EINVAL; 412 return -1; 413 } 414 415 rc = sock->net_impl->get_placement_id(sock, &placement_id); 416 if (!rc && (placement_id != 0)) { 417 spdk_sock_map_release(placement_id); 418 } 419 420 rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock); 421 if (rc == 0) { 422 TAILQ_REMOVE(&group_impl->socks, sock, link); 423 sock->cb_fn = NULL; 424 sock->cb_arg = NULL; 425 } 426 427 return rc; 428 } 429 430 int 431 spdk_sock_group_poll(struct spdk_sock_group *group) 432 { 433 return spdk_sock_group_poll_count(group, MAX_EVENTS_PER_POLL); 434 } 435 436 static int 437 spdk_sock_group_impl_poll_count(struct spdk_sock_group_impl *group_impl, 438 struct spdk_sock_group *group, 439 int max_events) 440 { 441 struct spdk_sock *socks[MAX_EVENTS_PER_POLL]; 442 int num_events, i; 443 444 if (TAILQ_EMPTY(&group_impl->socks)) { 445 return 0; 446 } 447 448 num_events = group_impl->net_impl->group_impl_poll(group_impl, max_events, socks); 449 if (num_events == -1) { 450 return -1; 451 } 452 453 for (i = 0; i < num_events; i++) { 454 struct spdk_sock *sock = socks[i]; 455 456 assert(sock->cb_fn != NULL); 457 sock->cb_fn(sock->cb_arg, group, sock); 458 } 459 return num_events; 460 } 461 462 int 463 spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events) 464 { 465 struct spdk_sock_group_impl *group_impl = NULL; 466 int rc, num_events = 0; 467 468 if (max_events < 1) { 469 errno = -EINVAL; 470 return -1; 471 } 472 473 /* 474 * Only poll for up to 32 events at a time - if more events are pending, 475 * the next call to this function will reap them. 476 */ 477 if (max_events > MAX_EVENTS_PER_POLL) { 478 max_events = MAX_EVENTS_PER_POLL; 479 } 480 481 STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { 482 rc = spdk_sock_group_impl_poll_count(group_impl, group, max_events); 483 if (rc < 0) { 484 num_events = -1; 485 SPDK_ERRLOG("group_impl_poll_count for net(%s) failed\n", 486 group_impl->net_impl->name); 487 } else if (num_events >= 0) { 488 num_events += rc; 489 } 490 } 491 492 return num_events; 493 } 494 495 int 496 spdk_sock_group_close(struct spdk_sock_group **group) 497 { 498 struct spdk_sock_group_impl *group_impl = NULL, *tmp; 499 int rc; 500 501 if (*group == NULL) { 502 errno = EBADF; 503 return -1; 504 } 505 506 STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { 507 if (!TAILQ_EMPTY(&group_impl->socks)) { 508 errno = EBUSY; 509 return -1; 510 } 511 } 512 513 STAILQ_FOREACH_SAFE(group_impl, &(*group)->group_impls, link, tmp) { 514 rc = group_impl->net_impl->group_impl_close(group_impl); 515 if (rc != 0) { 516 SPDK_ERRLOG("group_impl_close for net(%s) failed\n", 517 group_impl->net_impl->name); 518 } 519 free(group_impl); 520 } 521 522 spdk_sock_remove_sock_group_from_map_table(*group); 523 free(*group); 524 *group = NULL; 525 526 return 0; 527 } 528 529 void 530 spdk_net_impl_register(struct spdk_net_impl *impl) 531 { 532 if (!strcmp("posix", impl->name)) { 533 STAILQ_INSERT_TAIL(&g_net_impls, impl, link); 534 } else { 535 STAILQ_INSERT_HEAD(&g_net_impls, impl, link); 536 } 537 } 538