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 int 216 iscsi_parse_redirect_addr(struct sockaddr_storage *sa, 217 const char *host, const char *port) 218 { 219 struct addrinfo hints, *res; 220 int rc; 221 222 if (host == NULL || port == NULL) { 223 return -EINVAL; 224 } 225 226 memset(&hints, 0, sizeof(hints)); 227 hints.ai_family = PF_UNSPEC; 228 hints.ai_socktype = SOCK_STREAM; 229 hints.ai_flags = AI_NUMERICSERV; 230 hints.ai_flags |= AI_NUMERICHOST; 231 rc = getaddrinfo(host, port, &hints, &res); 232 if (rc != 0) { 233 SPDK_ERRLOG("getaddinrfo failed: %s (%d)\n", gai_strerror(rc), rc); 234 return -EINVAL; 235 } 236 237 if (res->ai_addrlen > sizeof(*sa)) { 238 SPDK_ERRLOG("getaddrinfo() ai_addrlen %zu too large\n", 239 (size_t)res->ai_addrlen); 240 rc = -EINVAL; 241 } else { 242 memcpy(sa, res->ai_addr, res->ai_addrlen); 243 } 244 245 freeaddrinfo(res); 246 return rc; 247 } 248 249 struct spdk_iscsi_portal_grp * 250 iscsi_portal_grp_create(int tag, bool is_private) 251 { 252 struct spdk_iscsi_portal_grp *pg = malloc(sizeof(*pg)); 253 254 if (!pg) { 255 SPDK_ERRLOG("malloc() failed for portal group\n"); 256 return NULL; 257 } 258 259 pg->ref = 0; 260 pg->tag = tag; 261 pg->is_private = is_private; 262 263 pthread_mutex_lock(&g_iscsi.mutex); 264 pg->disable_chap = g_iscsi.disable_chap; 265 pg->require_chap = g_iscsi.require_chap; 266 pg->mutual_chap = g_iscsi.mutual_chap; 267 pg->chap_group = g_iscsi.chap_group; 268 pthread_mutex_unlock(&g_iscsi.mutex); 269 270 TAILQ_INIT(&pg->head); 271 272 return pg; 273 } 274 275 void 276 iscsi_portal_grp_destroy(struct spdk_iscsi_portal_grp *pg) 277 { 278 struct spdk_iscsi_portal *p; 279 280 assert(pg != NULL); 281 282 SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_destroy\n"); 283 while (!TAILQ_EMPTY(&pg->head)) { 284 p = TAILQ_FIRST(&pg->head); 285 TAILQ_REMOVE(&pg->head, p, per_pg_tailq); 286 iscsi_portal_destroy(p); 287 } 288 free(pg); 289 } 290 291 int 292 iscsi_portal_grp_register(struct spdk_iscsi_portal_grp *pg) 293 { 294 int rc = -1; 295 struct spdk_iscsi_portal_grp *tmp; 296 297 assert(pg != NULL); 298 299 pthread_mutex_lock(&g_iscsi.mutex); 300 tmp = iscsi_portal_grp_find_by_tag(pg->tag); 301 if (tmp == NULL) { 302 TAILQ_INSERT_TAIL(&g_iscsi.pg_head, pg, tailq); 303 rc = 0; 304 } 305 pthread_mutex_unlock(&g_iscsi.mutex); 306 return rc; 307 } 308 309 void 310 iscsi_portal_grp_add_portal(struct spdk_iscsi_portal_grp *pg, 311 struct spdk_iscsi_portal *p) 312 { 313 assert(pg != NULL); 314 assert(p != NULL); 315 316 p->group = pg; 317 TAILQ_INSERT_TAIL(&pg->head, p, per_pg_tailq); 318 } 319 320 struct spdk_iscsi_portal * 321 iscsi_portal_grp_find_portal_by_addr(struct spdk_iscsi_portal_grp *pg, 322 const char *host, const char *port) 323 { 324 struct spdk_iscsi_portal *p; 325 326 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 327 if (!strcmp(p->host, host) && !strcmp(p->port, port)) { 328 return p; 329 } 330 } 331 332 return NULL; 333 } 334 335 int 336 iscsi_portal_grp_set_chap_params(struct spdk_iscsi_portal_grp *pg, 337 bool disable_chap, bool require_chap, 338 bool mutual_chap, int32_t chap_group) 339 { 340 if (!iscsi_check_chap_params(disable_chap, require_chap, 341 mutual_chap, chap_group)) { 342 return -EINVAL; 343 } 344 345 pg->disable_chap = disable_chap; 346 pg->require_chap = require_chap; 347 pg->mutual_chap = mutual_chap; 348 pg->chap_group = chap_group; 349 350 return 0; 351 } 352 353 struct spdk_iscsi_portal_grp * 354 iscsi_portal_grp_find_by_tag(int tag) 355 { 356 struct spdk_iscsi_portal_grp *pg; 357 358 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 359 if (pg->tag == tag) { 360 return pg; 361 } 362 } 363 364 return NULL; 365 } 366 367 void 368 iscsi_portal_grps_destroy(void) 369 { 370 struct spdk_iscsi_portal_grp *pg; 371 372 SPDK_DEBUGLOG(iscsi, "iscsi_portal_grps_destroy\n"); 373 pthread_mutex_lock(&g_iscsi.mutex); 374 while (!TAILQ_EMPTY(&g_iscsi.pg_head)) { 375 pg = TAILQ_FIRST(&g_iscsi.pg_head); 376 TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq); 377 pthread_mutex_unlock(&g_iscsi.mutex); 378 iscsi_portal_grp_destroy(pg); 379 pthread_mutex_lock(&g_iscsi.mutex); 380 } 381 pthread_mutex_unlock(&g_iscsi.mutex); 382 } 383 384 int 385 iscsi_portal_grp_open(struct spdk_iscsi_portal_grp *pg) 386 { 387 struct spdk_iscsi_portal *p; 388 int rc; 389 390 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 391 rc = iscsi_portal_open(p); 392 if (rc < 0) { 393 return rc; 394 } 395 } 396 return 0; 397 } 398 399 static void 400 iscsi_portal_grp_close(struct spdk_iscsi_portal_grp *pg) 401 { 402 struct spdk_iscsi_portal *p; 403 404 TAILQ_FOREACH(p, &pg->head, per_pg_tailq) { 405 iscsi_portal_close(p); 406 } 407 } 408 409 void 410 iscsi_portal_grp_close_all(void) 411 { 412 struct spdk_iscsi_portal_grp *pg; 413 414 SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_close_all\n"); 415 pthread_mutex_lock(&g_iscsi.mutex); 416 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 417 iscsi_portal_grp_close(pg); 418 } 419 pthread_mutex_unlock(&g_iscsi.mutex); 420 } 421 422 struct spdk_iscsi_portal_grp * 423 iscsi_portal_grp_unregister(int tag) 424 { 425 struct spdk_iscsi_portal_grp *pg; 426 427 pthread_mutex_lock(&g_iscsi.mutex); 428 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 429 if (pg->tag == tag) { 430 TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq); 431 pthread_mutex_unlock(&g_iscsi.mutex); 432 return pg; 433 } 434 } 435 pthread_mutex_unlock(&g_iscsi.mutex); 436 return NULL; 437 } 438 439 void 440 iscsi_portal_grp_release(struct spdk_iscsi_portal_grp *pg) 441 { 442 iscsi_portal_grp_close(pg); 443 iscsi_portal_grp_destroy(pg); 444 } 445 446 static void 447 iscsi_portal_grp_info_json(struct spdk_iscsi_portal_grp *pg, 448 struct spdk_json_write_ctx *w) 449 { 450 struct spdk_iscsi_portal *portal; 451 452 spdk_json_write_object_begin(w); 453 454 spdk_json_write_named_int32(w, "tag", pg->tag); 455 456 spdk_json_write_named_array_begin(w, "portals"); 457 TAILQ_FOREACH(portal, &pg->head, per_pg_tailq) { 458 spdk_json_write_object_begin(w); 459 460 spdk_json_write_named_string(w, "host", portal->host); 461 spdk_json_write_named_string(w, "port", portal->port); 462 463 spdk_json_write_object_end(w); 464 } 465 spdk_json_write_array_end(w); 466 467 spdk_json_write_named_bool(w, "private", pg->is_private); 468 469 spdk_json_write_object_end(w); 470 } 471 472 static void 473 iscsi_portal_grp_config_json(struct spdk_iscsi_portal_grp *pg, 474 struct spdk_json_write_ctx *w) 475 { 476 spdk_json_write_object_begin(w); 477 478 spdk_json_write_named_string(w, "method", "iscsi_create_portal_group"); 479 480 spdk_json_write_name(w, "params"); 481 iscsi_portal_grp_info_json(pg, w); 482 483 spdk_json_write_object_end(w); 484 } 485 486 void 487 iscsi_portal_grps_info_json(struct spdk_json_write_ctx *w) 488 { 489 struct spdk_iscsi_portal_grp *pg; 490 491 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 492 iscsi_portal_grp_info_json(pg, w); 493 } 494 } 495 496 void 497 iscsi_portal_grps_config_json(struct spdk_json_write_ctx *w) 498 { 499 struct spdk_iscsi_portal_grp *pg; 500 501 TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) { 502 iscsi_portal_grp_config_json(pg, w); 503 } 504 } 505