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/sock.h" 38 #include "spdk/string.h" 39 40 #include "spdk/log.h" 41 42 #include "iscsi/iscsi.h" 43 #include "iscsi/conn.h" 44 #include "iscsi/portal_grp.h" 45 #include "iscsi/tgt_node.h" 46 47 #define PORTNUMSTRLEN 32 48 #define ACCEPT_TIMEOUT_US 1000 /* 1ms */ 49 50 static int 51 iscsi_portal_accept(void *arg) 52 { 53 struct spdk_iscsi_portal *portal = arg; 54 struct spdk_sock *sock; 55 int rc; 56 int count = 0; 57 58 if (portal->sock == NULL) { 59 return -1; 60 } 61 62 while (1) { 63 sock = spdk_sock_accept(portal->sock); 64 if (sock != NULL) { 65 rc = iscsi_conn_construct(portal, sock); 66 if (rc < 0) { 67 spdk_sock_close(&sock); 68 SPDK_ERRLOG("spdk_iscsi_connection_construct() failed\n"); 69 break; 70 } 71 count++; 72 } else { 73 if (errno != EAGAIN && errno != EWOULDBLOCK) { 74 SPDK_ERRLOG("accept error(%d): %s\n", errno, spdk_strerror(errno)); 75 } 76 break; 77 } 78 } 79 80 return count; 81 } 82 83 static struct spdk_iscsi_portal * 84 iscsi_portal_find_by_addr(const char *host, const char *port) 85 { 86 struct spdk_iscsi_portal *p; 87 88 TAILQ_FOREACH(p, &g_iscsi.portal_head, g_tailq) { 89 if (!strcmp(p->host, host) && !strcmp(p->port, port)) { 90 return p; 91 } 92 } 93 94 return NULL; 95 } 96 97 /* Assumes caller allocated host and port strings on the heap */ 98 struct spdk_iscsi_portal * 99 iscsi_portal_create(const char *host, const char *port) 100 { 101 struct spdk_iscsi_portal *p = NULL, *tmp; 102 103 assert(host != NULL); 104 assert(port != NULL); 105 106 if (strlen(host) > MAX_PORTAL_ADDR || strlen(port) > MAX_PORTAL_PORT) { 107 return NULL; 108 } 109 110 p = calloc(1, sizeof(*p)); 111 if (!p) { 112 SPDK_ERRLOG("calloc() failed for portal\n"); 113 return NULL; 114 } 115 116 /* check and overwrite abbreviation of wildcard */ 117 if (strcasecmp(host, "[*]") == 0) { 118 SPDK_WARNLOG("Please use \"[::]\" as IPv6 wildcard\n"); 119 SPDK_WARNLOG("Convert \"[*]\" to \"[::]\" automatically\n"); 120 SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)"); 121 snprintf(p->host, sizeof(p->host), "[::]"); 122 } else if (strcasecmp(host, "*") == 0) { 123 SPDK_WARNLOG("Please use \"0.0.0.0\" as IPv4 wildcard\n"); 124 SPDK_WARNLOG("Convert \"*\" to \"0.0.0.0\" automatically\n"); 125 SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)"); 126 snprintf(p->host, sizeof(p->host), "0.0.0.0"); 127 } else { 128 memcpy(p->host, host, strlen(host)); 129 } 130 131 memcpy(p->port, port, strlen(port)); 132 133 p->sock = NULL; 134 p->group = NULL; /* set at a later time by caller */ 135 p->acceptor_poller = NULL; 136 137 pthread_mutex_lock(&g_iscsi.mutex); 138 tmp = iscsi_portal_find_by_addr(host, port); 139 if (tmp != NULL) { 140 pthread_mutex_unlock(&g_iscsi.mutex); 141 SPDK_ERRLOG("portal (%s, %s) already exists\n", host, port); 142 goto error_out; 143 } 144 145 TAILQ_INSERT_TAIL(&g_iscsi.portal_head, p, g_tailq); 146 pthread_mutex_unlock(&g_iscsi.mutex); 147 148 return p; 149 150 error_out: 151 free(p); 152 153 return NULL; 154 } 155 156 void 157 iscsi_portal_destroy(struct spdk_iscsi_portal *p) 158 { 159 assert(p != NULL); 160 161 SPDK_DEBUGLOG(iscsi, "iscsi_portal_destroy\n"); 162 163 pthread_mutex_lock(&g_iscsi.mutex); 164 TAILQ_REMOVE(&g_iscsi.portal_head, p, g_tailq); 165 pthread_mutex_unlock(&g_iscsi.mutex); 166 167 free(p); 168 169 } 170 171 static int 172 iscsi_portal_open(struct spdk_iscsi_portal *p) 173 { 174 struct spdk_sock *sock; 175 int port; 176 177 if (p->sock != NULL) { 178 SPDK_ERRLOG("portal (%s, %s) is already opened\n", 179 p->host, p->port); 180 return -1; 181 } 182 183 port = (int)strtol(p->port, NULL, 0); 184 sock = spdk_sock_listen(p->host, port, NULL); 185 if (sock == NULL) { 186 SPDK_ERRLOG("listen error %.64s.%d\n", p->host, port); 187 return -1; 188 } 189 190 p->sock = sock; 191 192 /* 193 * When the portal is created by config file, incoming connection 194 * requests for the socket are pended to accept until reactors start. 195 * However the gap between listen() and accept() will be slight and 196 * the requests will be queued by the nonzero backlog of the socket 197 * or resend by TCP. 198 */ 199 p->acceptor_poller = SPDK_POLLER_REGISTER(iscsi_portal_accept, p, ACCEPT_TIMEOUT_US); 200 201 return 0; 202 } 203 204 static void 205 iscsi_portal_close(struct spdk_iscsi_portal *p) 206 { 207 if (p->sock) { 208 SPDK_DEBUGLOG(iscsi, "close portal (%s, %s)\n", 209 p->host, p->port); 210 spdk_poller_unregister(&p->acceptor_poller); 211 spdk_sock_close(&p->sock); 212 } 213 } 214 215 static void 216 iscsi_portal_pause(struct spdk_iscsi_portal *p) 217 { 218 assert(p->acceptor_poller != NULL); 219 220 spdk_poller_pause(p->acceptor_poller); 221 } 222 223 static void 224 iscsi_portal_resume(struct spdk_iscsi_portal *p) 225 { 226 assert(p->acceptor_poller != NULL); 227 228 spdk_poller_resume(p->acceptor_poller); 229 } 230 231 int 232 iscsi_parse_redirect_addr(struct sockaddr_storage *sa, 233 const char *host, const char *port) 234 { 235 struct addrinfo hints, *res; 236 int rc; 237 238 if (host == NULL || port == NULL) { 239 return -EINVAL; 240 } 241 242 memset(&hints, 0, sizeof(hints)); 243 hints.ai_family = PF_UNSPEC; 244 hints.ai_socktype = SOCK_STREAM; 245 hints.ai_flags = AI_NUMERICSERV; 246 hints.ai_flags |= AI_NUMERICHOST; 247 rc = getaddrinfo(host, port, &hints, &res); 248 if (rc != 0) { 249 SPDK_ERRLOG("getaddinrfo failed: %s (%d)\n", gai_strerror(rc), rc); 250 return -EINVAL; 251 } 252 253 if (res->ai_addrlen > sizeof(*sa)) { 254 SPDK_ERRLOG("getaddrinfo() ai_addrlen %zu too large\n", 255 (size_t)res->ai_addrlen); 256 rc = -EINVAL; 257 } else { 258 memcpy(sa, res->ai_addr, res->ai_addrlen); 259 } 260 261 freeaddrinfo(res); 262 return rc; 263 } 264 265 struct spdk_iscsi_portal_grp * 266 iscsi_portal_grp_create(int tag, bool is_private) 267 { 268 struct spdk_iscsi_portal_grp *pg = malloc(sizeof(*pg)); 269 270 if (!pg) { 271 SPDK_ERRLOG("malloc() failed for portal group\n"); 272 return NULL; 273 } 274 275 pg->ref = 0; 276 pg->tag = tag; 277 pg->is_private = is_private; 278 279 pthread_mutex_lock(&g_iscsi.mutex); 280 pg->disable_chap = g_iscsi.disable_chap; 281 pg->require_chap = g_iscsi.require_chap; 282 pg->mutual_chap = g_iscsi.mutual_chap; 283 pg->chap_group = g_iscsi.chap_group; 284 pthread_mutex_unlock(&g_iscsi.mutex); 285 286 TAILQ_INIT(&pg->head); 287 288 return pg; 289 } 290 291 void 292 iscsi_portal_grp_destroy(struct spdk_iscsi_portal_grp *pg) 293 { 294 struct spdk_iscsi_portal *p; 295 296 assert(pg != NULL); 297 298 SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_destroy\n"); 299 while (!TAILQ_EMPTY(&pg->head)) { 300 p = TAILQ_FIRST(&pg->head); 301 TAILQ_REMOVE(&pg->head, p, per_pg_tailq); 302 iscsi_portal_destroy(p); 303 } 304 free(pg); 305 } 306 307 int 308 iscsi_portal_grp_register(struct spdk_iscsi_portal_grp *pg) 309 { 310 int rc = -1; 311 struct spdk_iscsi_portal_grp *tmp; 312 313 assert(pg != NULL); 314 315 pthread_mutex_lock(&g_iscsi.mutex); 316 tmp = iscsi_portal_grp_find_by_tag(pg->tag); 317 if (tmp == NULL) { 318 TAILQ_INSERT_TAIL(&g_iscsi.pg_head, pg, tailq); 319 rc = 0; 320 } 321 pthread_mutex_unlock(&g_iscsi.mutex); 322 return rc; 323 } 324 325 void 326 iscsi_portal_grp_add_portal(struct spdk_iscsi_portal_grp *pg, 327 struct spdk_iscsi_portal *p) 328 { 329 assert(pg != NULL); 330 assert(p != NULL); 331 332 p->group = pg; 333 TAILQ_INSERT_TAIL(&pg->head, p, per_pg_tailq); 334 } 335 336 struct spdk_iscsi_portal * 337 iscsi_portal_grp_find_portal_by_addr(struct spdk_iscsi_portal_grp *pg, 338 const char *host, const char *port) 339 { 340 struct spdk_iscsi_portal *p; 341 342 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 343 if (!strcmp(p->host, host) && !strcmp(p->port, port)) { 344 return p; 345 } 346 } 347 348 return NULL; 349 } 350 351 int 352 iscsi_portal_grp_set_chap_params(struct spdk_iscsi_portal_grp *pg, 353 bool disable_chap, bool require_chap, 354 bool mutual_chap, int32_t chap_group) 355 { 356 if (!iscsi_check_chap_params(disable_chap, require_chap, 357 mutual_chap, chap_group)) { 358 return -EINVAL; 359 } 360 361 pg->disable_chap = disable_chap; 362 pg->require_chap = require_chap; 363 pg->mutual_chap = mutual_chap; 364 pg->chap_group = chap_group; 365 366 return 0; 367 } 368 369 struct spdk_iscsi_portal_grp * 370 iscsi_portal_grp_find_by_tag(int tag) 371 { 372 struct spdk_iscsi_portal_grp *pg; 373 374 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 375 if (pg->tag == tag) { 376 return pg; 377 } 378 } 379 380 return NULL; 381 } 382 383 void 384 iscsi_portal_grps_destroy(void) 385 { 386 struct spdk_iscsi_portal_grp *pg; 387 388 SPDK_DEBUGLOG(iscsi, "iscsi_portal_grps_destroy\n"); 389 pthread_mutex_lock(&g_iscsi.mutex); 390 while (!TAILQ_EMPTY(&g_iscsi.pg_head)) { 391 pg = TAILQ_FIRST(&g_iscsi.pg_head); 392 TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq); 393 pthread_mutex_unlock(&g_iscsi.mutex); 394 iscsi_portal_grp_destroy(pg); 395 pthread_mutex_lock(&g_iscsi.mutex); 396 } 397 pthread_mutex_unlock(&g_iscsi.mutex); 398 } 399 400 int 401 iscsi_portal_grp_open(struct spdk_iscsi_portal_grp *pg, bool pause) 402 { 403 struct spdk_iscsi_portal *p; 404 int rc; 405 406 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 407 rc = iscsi_portal_open(p); 408 if (rc < 0) { 409 return rc; 410 } 411 412 if (pause) { 413 iscsi_portal_pause(p); 414 } 415 } 416 return 0; 417 } 418 419 static void 420 iscsi_portal_grp_close(struct spdk_iscsi_portal_grp *pg) 421 { 422 struct spdk_iscsi_portal *p; 423 424 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 425 iscsi_portal_close(p); 426 } 427 } 428 429 void 430 iscsi_portal_grp_resume(struct spdk_iscsi_portal_grp *pg) 431 { 432 struct spdk_iscsi_portal *p; 433 434 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 435 iscsi_portal_resume(p); 436 } 437 } 438 439 void 440 iscsi_portal_grp_close_all(void) 441 { 442 struct spdk_iscsi_portal_grp *pg; 443 444 SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_close_all\n"); 445 pthread_mutex_lock(&g_iscsi.mutex); 446 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 447 iscsi_portal_grp_close(pg); 448 } 449 pthread_mutex_unlock(&g_iscsi.mutex); 450 } 451 452 struct spdk_iscsi_portal_grp * 453 iscsi_portal_grp_unregister(int tag) 454 { 455 struct spdk_iscsi_portal_grp *pg; 456 457 pthread_mutex_lock(&g_iscsi.mutex); 458 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 459 if (pg->tag == tag) { 460 TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq); 461 pthread_mutex_unlock(&g_iscsi.mutex); 462 return pg; 463 } 464 } 465 pthread_mutex_unlock(&g_iscsi.mutex); 466 return NULL; 467 } 468 469 void 470 iscsi_portal_grp_release(struct spdk_iscsi_portal_grp *pg) 471 { 472 iscsi_portal_grp_close(pg); 473 iscsi_portal_grp_destroy(pg); 474 } 475 476 static void 477 iscsi_portal_grp_info_json(struct spdk_iscsi_portal_grp *pg, 478 struct spdk_json_write_ctx *w) 479 { 480 struct spdk_iscsi_portal *portal; 481 482 spdk_json_write_object_begin(w); 483 484 spdk_json_write_named_int32(w, "tag", pg->tag); 485 486 spdk_json_write_named_array_begin(w, "portals"); 487 TAILQ_FOREACH(portal, &pg->head, per_pg_tailq) { 488 spdk_json_write_object_begin(w); 489 490 spdk_json_write_named_string(w, "host", portal->host); 491 spdk_json_write_named_string(w, "port", portal->port); 492 493 spdk_json_write_object_end(w); 494 } 495 spdk_json_write_array_end(w); 496 497 spdk_json_write_named_bool(w, "private", pg->is_private); 498 499 spdk_json_write_object_end(w); 500 } 501 502 static void 503 iscsi_portal_grp_config_json(struct spdk_iscsi_portal_grp *pg, 504 struct spdk_json_write_ctx *w) 505 { 506 spdk_json_write_object_begin(w); 507 508 spdk_json_write_named_string(w, "method", "iscsi_create_portal_group"); 509 510 spdk_json_write_name(w, "params"); 511 iscsi_portal_grp_info_json(pg, w); 512 513 spdk_json_write_object_end(w); 514 } 515 516 void 517 iscsi_portal_grps_info_json(struct spdk_json_write_ctx *w) 518 { 519 struct spdk_iscsi_portal_grp *pg; 520 521 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 522 iscsi_portal_grp_info_json(pg, w); 523 } 524 } 525 526 void 527 iscsi_portal_grps_config_json(struct spdk_json_write_ctx *w) 528 { 529 struct spdk_iscsi_portal_grp *pg; 530 531 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 532 iscsi_portal_grp_config_json(pg, w); 533 } 534 } 535