1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>. 5 * Copyright (c) Intel Corporation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * * Neither the name of Intel Corporation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include "spdk/stdinc.h" 36 37 #include "spdk/conf.h" 38 #include "spdk/sock.h" 39 #include "spdk/string.h" 40 41 #include "spdk/log.h" 42 43 #include "iscsi/iscsi.h" 44 #include "iscsi/conn.h" 45 #include "iscsi/portal_grp.h" 46 #include "iscsi/tgt_node.h" 47 48 #define PORTNUMSTRLEN 32 49 #define ACCEPT_TIMEOUT_US 1000 /* 1ms */ 50 51 static int 52 iscsi_portal_accept(void *arg) 53 { 54 struct spdk_iscsi_portal *portal = arg; 55 struct spdk_sock *sock; 56 int rc; 57 int count = 0; 58 59 if (portal->sock == NULL) { 60 return -1; 61 } 62 63 while (1) { 64 sock = spdk_sock_accept(portal->sock); 65 if (sock != NULL) { 66 rc = iscsi_conn_construct(portal, sock); 67 if (rc < 0) { 68 spdk_sock_close(&sock); 69 SPDK_ERRLOG("spdk_iscsi_connection_construct() failed\n"); 70 break; 71 } 72 count++; 73 } else { 74 if (errno != EAGAIN && errno != EWOULDBLOCK) { 75 SPDK_ERRLOG("accept error(%d): %s\n", errno, spdk_strerror(errno)); 76 } 77 break; 78 } 79 } 80 81 return count; 82 } 83 84 static struct spdk_iscsi_portal * 85 iscsi_portal_find_by_addr(const char *host, const char *port) 86 { 87 struct spdk_iscsi_portal *p; 88 89 TAILQ_FOREACH(p, &g_iscsi.portal_head, g_tailq) { 90 if (!strcmp(p->host, host) && !strcmp(p->port, port)) { 91 return p; 92 } 93 } 94 95 return NULL; 96 } 97 98 /* Assumes caller allocated host and port strings on the heap */ 99 struct spdk_iscsi_portal * 100 iscsi_portal_create(const char *host, const char *port) 101 { 102 struct spdk_iscsi_portal *p = NULL, *tmp; 103 104 assert(host != NULL); 105 assert(port != NULL); 106 107 if (strlen(host) > MAX_PORTAL_ADDR || strlen(port) > MAX_PORTAL_PORT) { 108 return NULL; 109 } 110 111 p = calloc(1, sizeof(*p)); 112 if (!p) { 113 SPDK_ERRLOG("calloc() failed for portal\n"); 114 return NULL; 115 } 116 117 /* check and overwrite abbreviation of wildcard */ 118 if (strcasecmp(host, "[*]") == 0) { 119 SPDK_WARNLOG("Please use \"[::]\" as IPv6 wildcard\n"); 120 SPDK_WARNLOG("Convert \"[*]\" to \"[::]\" automatically\n"); 121 SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)"); 122 snprintf(p->host, sizeof(p->host), "[::]"); 123 } else if (strcasecmp(host, "*") == 0) { 124 SPDK_WARNLOG("Please use \"0.0.0.0\" as IPv4 wildcard\n"); 125 SPDK_WARNLOG("Convert \"*\" to \"0.0.0.0\" automatically\n"); 126 SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)"); 127 snprintf(p->host, sizeof(p->host), "0.0.0.0"); 128 } else { 129 memcpy(p->host, host, strlen(host)); 130 } 131 132 memcpy(p->port, port, strlen(port)); 133 134 p->sock = NULL; 135 p->group = NULL; /* set at a later time by caller */ 136 p->acceptor_poller = NULL; 137 138 pthread_mutex_lock(&g_iscsi.mutex); 139 tmp = iscsi_portal_find_by_addr(host, port); 140 if (tmp != NULL) { 141 pthread_mutex_unlock(&g_iscsi.mutex); 142 SPDK_ERRLOG("portal (%s, %s) already exists\n", host, port); 143 goto error_out; 144 } 145 146 TAILQ_INSERT_TAIL(&g_iscsi.portal_head, p, g_tailq); 147 pthread_mutex_unlock(&g_iscsi.mutex); 148 149 return p; 150 151 error_out: 152 free(p); 153 154 return NULL; 155 } 156 157 void 158 iscsi_portal_destroy(struct spdk_iscsi_portal *p) 159 { 160 assert(p != NULL); 161 162 SPDK_DEBUGLOG(iscsi, "iscsi_portal_destroy\n"); 163 164 pthread_mutex_lock(&g_iscsi.mutex); 165 TAILQ_REMOVE(&g_iscsi.portal_head, p, g_tailq); 166 pthread_mutex_unlock(&g_iscsi.mutex); 167 168 free(p); 169 170 } 171 172 static int 173 iscsi_portal_open(struct spdk_iscsi_portal *p) 174 { 175 struct spdk_sock *sock; 176 int port; 177 178 if (p->sock != NULL) { 179 SPDK_ERRLOG("portal (%s, %s) is already opened\n", 180 p->host, p->port); 181 return -1; 182 } 183 184 port = (int)strtol(p->port, NULL, 0); 185 sock = spdk_sock_listen(p->host, port, NULL); 186 if (sock == NULL) { 187 SPDK_ERRLOG("listen error %.64s.%d\n", p->host, port); 188 return -1; 189 } 190 191 p->sock = sock; 192 193 /* 194 * When the portal is created by config file, incoming connection 195 * requests for the socket are pended to accept until reactors start. 196 * However the gap between listen() and accept() will be slight and 197 * the requests will be queued by the nonzero backlog of the socket 198 * or resend by TCP. 199 */ 200 p->acceptor_poller = SPDK_POLLER_REGISTER(iscsi_portal_accept, p, ACCEPT_TIMEOUT_US); 201 202 return 0; 203 } 204 205 static void 206 iscsi_portal_close(struct spdk_iscsi_portal *p) 207 { 208 if (p->sock) { 209 SPDK_DEBUGLOG(iscsi, "close portal (%s, %s)\n", 210 p->host, p->port); 211 spdk_poller_unregister(&p->acceptor_poller); 212 spdk_sock_close(&p->sock); 213 } 214 } 215 216 static int 217 iscsi_parse_portal(const char *portalstring, struct spdk_iscsi_portal **ip) 218 { 219 char host[MAX_PORTAL_ADDR + 1] = {}; 220 char port[MAX_PORTAL_PORT + 1] = {}; 221 int len; 222 const char *p; 223 224 if (portalstring == NULL) { 225 SPDK_ERRLOG("portal error\n"); 226 return -EINVAL; 227 } 228 229 /* IP address */ 230 if (portalstring[0] == '[') { 231 /* IPv6 */ 232 p = strchr(portalstring + 1, ']'); 233 if (p == NULL) { 234 SPDK_ERRLOG("portal error\n"); 235 return -EINVAL; 236 } 237 p++; 238 } else { 239 /* IPv4 */ 240 p = strchr(portalstring, ':'); 241 if (p == NULL) { 242 p = portalstring + strlen(portalstring); 243 } 244 } 245 246 len = p - portalstring; 247 if (len > MAX_PORTAL_ADDR) { 248 return -EINVAL; 249 } 250 memcpy(host, portalstring, len); 251 host[len] = '\0'; 252 253 /* Port number (IPv4 and IPv6 are the same) */ 254 if (p[0] == '\0') { 255 snprintf(port, MAX_PORTAL_PORT, "%d", DEFAULT_PORT); 256 } else { 257 p++; 258 len = strlen(p); 259 if (len > MAX_PORTAL_PORT) { 260 return -EINVAL; 261 } 262 memcpy(port, p, len); 263 port[len] = '\0'; 264 } 265 266 *ip = iscsi_portal_create(host, port); 267 if (!*ip) { 268 return -EINVAL; 269 } 270 271 return 0; 272 } 273 274 int 275 iscsi_parse_redirect_addr(struct sockaddr_storage *sa, 276 const char *host, const char *port) 277 { 278 struct addrinfo hints, *res; 279 int rc; 280 281 if (host == NULL || port == NULL) { 282 return -EINVAL; 283 } 284 285 memset(&hints, 0, sizeof(hints)); 286 hints.ai_family = PF_UNSPEC; 287 hints.ai_socktype = SOCK_STREAM; 288 hints.ai_flags = AI_NUMERICSERV; 289 hints.ai_flags |= AI_NUMERICHOST; 290 rc = getaddrinfo(host, port, &hints, &res); 291 if (rc != 0) { 292 SPDK_ERRLOG("getaddinrfo failed: %s (%d)\n", gai_strerror(rc), rc); 293 return -EINVAL; 294 } 295 296 if (res->ai_addrlen > sizeof(*sa)) { 297 SPDK_ERRLOG("getaddrinfo() ai_addrlen %zu too large\n", 298 (size_t)res->ai_addrlen); 299 rc = -EINVAL; 300 } else { 301 memcpy(sa, res->ai_addr, res->ai_addrlen); 302 } 303 304 freeaddrinfo(res); 305 return rc; 306 } 307 308 struct spdk_iscsi_portal_grp * 309 iscsi_portal_grp_create(int tag, bool is_private) 310 { 311 struct spdk_iscsi_portal_grp *pg = malloc(sizeof(*pg)); 312 313 if (!pg) { 314 SPDK_ERRLOG("malloc() failed for portal group\n"); 315 return NULL; 316 } 317 318 pg->ref = 0; 319 pg->tag = tag; 320 pg->is_private = is_private; 321 322 pthread_mutex_lock(&g_iscsi.mutex); 323 pg->disable_chap = g_iscsi.disable_chap; 324 pg->require_chap = g_iscsi.require_chap; 325 pg->mutual_chap = g_iscsi.mutual_chap; 326 pg->chap_group = g_iscsi.chap_group; 327 pthread_mutex_unlock(&g_iscsi.mutex); 328 329 TAILQ_INIT(&pg->head); 330 331 return pg; 332 } 333 334 void 335 iscsi_portal_grp_destroy(struct spdk_iscsi_portal_grp *pg) 336 { 337 struct spdk_iscsi_portal *p; 338 339 assert(pg != NULL); 340 341 SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_destroy\n"); 342 while (!TAILQ_EMPTY(&pg->head)) { 343 p = TAILQ_FIRST(&pg->head); 344 TAILQ_REMOVE(&pg->head, p, per_pg_tailq); 345 iscsi_portal_destroy(p); 346 } 347 free(pg); 348 } 349 350 int 351 iscsi_portal_grp_register(struct spdk_iscsi_portal_grp *pg) 352 { 353 int rc = -1; 354 struct spdk_iscsi_portal_grp *tmp; 355 356 assert(pg != NULL); 357 358 pthread_mutex_lock(&g_iscsi.mutex); 359 tmp = iscsi_portal_grp_find_by_tag(pg->tag); 360 if (tmp == NULL) { 361 TAILQ_INSERT_TAIL(&g_iscsi.pg_head, pg, tailq); 362 rc = 0; 363 } 364 pthread_mutex_unlock(&g_iscsi.mutex); 365 return rc; 366 } 367 368 void 369 iscsi_portal_grp_add_portal(struct spdk_iscsi_portal_grp *pg, 370 struct spdk_iscsi_portal *p) 371 { 372 assert(pg != NULL); 373 assert(p != NULL); 374 375 p->group = pg; 376 TAILQ_INSERT_TAIL(&pg->head, p, per_pg_tailq); 377 } 378 379 struct spdk_iscsi_portal * 380 iscsi_portal_grp_find_portal_by_addr(struct spdk_iscsi_portal_grp *pg, 381 const char *host, const char *port) 382 { 383 struct spdk_iscsi_portal *p; 384 385 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 386 if (!strcmp(p->host, host) && !strcmp(p->port, port)) { 387 return p; 388 } 389 } 390 391 return NULL; 392 } 393 394 int 395 iscsi_portal_grp_set_chap_params(struct spdk_iscsi_portal_grp *pg, 396 bool disable_chap, bool require_chap, 397 bool mutual_chap, int32_t chap_group) 398 { 399 if (!iscsi_check_chap_params(disable_chap, require_chap, 400 mutual_chap, chap_group)) { 401 return -EINVAL; 402 } 403 404 pg->disable_chap = disable_chap; 405 pg->require_chap = require_chap; 406 pg->mutual_chap = mutual_chap; 407 pg->chap_group = chap_group; 408 409 return 0; 410 } 411 412 static int 413 iscsi_parse_portal_grp(struct spdk_conf_section *sp) 414 { 415 struct spdk_iscsi_portal_grp *pg; 416 struct spdk_iscsi_portal *p; 417 const char *val; 418 char *label, *portal; 419 int i = 0, rc = 0; 420 421 SPDK_DEBUGLOG(iscsi, "add portal group (from config file) %d\n", 422 spdk_conf_section_get_num(sp)); 423 424 val = spdk_conf_section_get_val(sp, "Comment"); 425 if (val != NULL) { 426 SPDK_DEBUGLOG(iscsi, "Comment %s\n", val); 427 } 428 429 pg = iscsi_portal_grp_create(spdk_conf_section_get_num(sp), false); 430 if (!pg) { 431 SPDK_ERRLOG("portal group malloc error (%s)\n", spdk_conf_section_get_name(sp)); 432 return -1; 433 } 434 435 for (i = 0; ; i++) { 436 label = spdk_conf_section_get_nmval(sp, "Portal", i, 0); 437 portal = spdk_conf_section_get_nmval(sp, "Portal", i, 1); 438 if (label == NULL || portal == NULL) { 439 break; 440 } 441 442 rc = iscsi_parse_portal(portal, &p); 443 if (rc < 0) { 444 SPDK_ERRLOG("parse portal error (%s)\n", portal); 445 goto error; 446 } 447 448 SPDK_DEBUGLOG(iscsi, 449 "RIndex=%d, Host=%s, Port=%s, Tag=%d\n", 450 i, p->host, p->port, spdk_conf_section_get_num(sp)); 451 452 iscsi_portal_grp_add_portal(pg, p); 453 } 454 455 rc = iscsi_portal_grp_open(pg); 456 if (rc != 0) { 457 SPDK_ERRLOG("portal_grp_open failed\n"); 458 goto error; 459 } 460 461 /* Add portal group to the end of the pg list */ 462 rc = iscsi_portal_grp_register(pg); 463 if (rc != 0) { 464 SPDK_ERRLOG("register portal failed\n"); 465 goto error; 466 } 467 468 return 0; 469 470 error: 471 iscsi_portal_grp_release(pg); 472 return -1; 473 } 474 475 struct spdk_iscsi_portal_grp * 476 iscsi_portal_grp_find_by_tag(int tag) 477 { 478 struct spdk_iscsi_portal_grp *pg; 479 480 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 481 if (pg->tag == tag) { 482 return pg; 483 } 484 } 485 486 return NULL; 487 } 488 489 int 490 iscsi_parse_portal_grps(void) 491 { 492 int rc = 0; 493 struct spdk_conf_section *sp; 494 495 sp = spdk_conf_first_section(NULL); 496 while (sp != NULL) { 497 if (spdk_conf_section_match_prefix(sp, "PortalGroup")) { 498 if (spdk_conf_section_get_num(sp) == 0) { 499 SPDK_ERRLOG("Group 0 is invalid\n"); 500 return -1; 501 } 502 503 /* Build portal group from cfg section PortalGroup */ 504 rc = iscsi_parse_portal_grp(sp); 505 if (rc < 0) { 506 SPDK_ERRLOG("parse_portal_group() failed\n"); 507 return -1; 508 } 509 } 510 sp = spdk_conf_next_section(sp); 511 } 512 return 0; 513 } 514 515 void 516 iscsi_portal_grps_destroy(void) 517 { 518 struct spdk_iscsi_portal_grp *pg; 519 520 SPDK_DEBUGLOG(iscsi, "iscsi_portal_grps_destroy\n"); 521 pthread_mutex_lock(&g_iscsi.mutex); 522 while (!TAILQ_EMPTY(&g_iscsi.pg_head)) { 523 pg = TAILQ_FIRST(&g_iscsi.pg_head); 524 TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq); 525 pthread_mutex_unlock(&g_iscsi.mutex); 526 iscsi_portal_grp_destroy(pg); 527 pthread_mutex_lock(&g_iscsi.mutex); 528 } 529 pthread_mutex_unlock(&g_iscsi.mutex); 530 } 531 532 int 533 iscsi_portal_grp_open(struct spdk_iscsi_portal_grp *pg) 534 { 535 struct spdk_iscsi_portal *p; 536 int rc; 537 538 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 539 rc = iscsi_portal_open(p); 540 if (rc < 0) { 541 return rc; 542 } 543 } 544 return 0; 545 } 546 547 static void 548 iscsi_portal_grp_close(struct spdk_iscsi_portal_grp *pg) 549 { 550 struct spdk_iscsi_portal *p; 551 552 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 553 iscsi_portal_close(p); 554 } 555 } 556 557 void 558 iscsi_portal_grp_close_all(void) 559 { 560 struct spdk_iscsi_portal_grp *pg; 561 562 SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_close_all\n"); 563 pthread_mutex_lock(&g_iscsi.mutex); 564 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 565 iscsi_portal_grp_close(pg); 566 } 567 pthread_mutex_unlock(&g_iscsi.mutex); 568 } 569 570 struct spdk_iscsi_portal_grp * 571 iscsi_portal_grp_unregister(int tag) 572 { 573 struct spdk_iscsi_portal_grp *pg; 574 575 pthread_mutex_lock(&g_iscsi.mutex); 576 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 577 if (pg->tag == tag) { 578 TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq); 579 pthread_mutex_unlock(&g_iscsi.mutex); 580 return pg; 581 } 582 } 583 pthread_mutex_unlock(&g_iscsi.mutex); 584 return NULL; 585 } 586 587 void 588 iscsi_portal_grp_release(struct spdk_iscsi_portal_grp *pg) 589 { 590 iscsi_portal_grp_close(pg); 591 iscsi_portal_grp_destroy(pg); 592 } 593 594 static const char *portal_group_section = \ 595 "\n" 596 "# Users must change the PortalGroup section(s) to match the IP addresses\n" 597 "# for their environment.\n" 598 "# PortalGroup sections define which network portals the iSCSI target\n" 599 "# will use to listen for incoming connections. These are also used to\n" 600 "# determine which targets are accessible over each portal group.\n" 601 "# Up to 1024 Portal directives are allowed. These define the network\n" 602 "# portals of the portal group. The user must specify a IP address\n" 603 "# for each network portal, and may optionally specify a port.\n" 604 "# If the port is omitted, 3260 will be used\n" 605 "# Syntax:\n" 606 "# Portal <Name> <IP address>[:<port>]\n"; 607 608 #define PORTAL_GROUP_TMPL \ 609 "[PortalGroup%d]\n" \ 610 " Comment \"Portal%d\"\n" 611 612 #define PORTAL_TMPL \ 613 " Portal DA1 %s:%s\n" 614 615 void 616 iscsi_portal_grps_config_text(FILE *fp) 617 { 618 struct spdk_iscsi_portal *p = NULL; 619 struct spdk_iscsi_portal_grp *pg = NULL; 620 621 /* Create portal group section */ 622 fprintf(fp, "%s", portal_group_section); 623 624 /* Dump portal groups */ 625 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 626 if (NULL == pg) { continue; } 627 fprintf(fp, PORTAL_GROUP_TMPL, pg->tag, pg->tag); 628 /* Dump portals */ 629 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 630 if (NULL == p) { continue; } 631 fprintf(fp, PORTAL_TMPL, p->host, p->port); 632 } 633 } 634 } 635 636 static void 637 iscsi_portal_grp_info_json(struct spdk_iscsi_portal_grp *pg, 638 struct spdk_json_write_ctx *w) 639 { 640 struct spdk_iscsi_portal *portal; 641 642 spdk_json_write_object_begin(w); 643 644 spdk_json_write_named_int32(w, "tag", pg->tag); 645 646 spdk_json_write_named_array_begin(w, "portals"); 647 TAILQ_FOREACH(portal, &pg->head, per_pg_tailq) { 648 spdk_json_write_object_begin(w); 649 650 spdk_json_write_named_string(w, "host", portal->host); 651 spdk_json_write_named_string(w, "port", portal->port); 652 653 spdk_json_write_object_end(w); 654 } 655 spdk_json_write_array_end(w); 656 657 spdk_json_write_named_bool(w, "private", pg->is_private); 658 659 spdk_json_write_object_end(w); 660 } 661 662 static void 663 iscsi_portal_grp_config_json(struct spdk_iscsi_portal_grp *pg, 664 struct spdk_json_write_ctx *w) 665 { 666 spdk_json_write_object_begin(w); 667 668 spdk_json_write_named_string(w, "method", "iscsi_create_portal_group"); 669 670 spdk_json_write_name(w, "params"); 671 iscsi_portal_grp_info_json(pg, w); 672 673 spdk_json_write_object_end(w); 674 } 675 676 void 677 iscsi_portal_grps_info_json(struct spdk_json_write_ctx *w) 678 { 679 struct spdk_iscsi_portal_grp *pg; 680 681 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 682 iscsi_portal_grp_info_json(pg, w); 683 } 684 } 685 686 void 687 iscsi_portal_grps_config_json(struct spdk_json_write_ctx *w) 688 { 689 struct spdk_iscsi_portal_grp *pg; 690 691 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 692 iscsi_portal_grp_config_json(pg, w); 693 } 694 } 695