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/string.h" 38 39 #include "spdk/log.h" 40 41 #include "iscsi/iscsi.h" 42 #include "iscsi/init_grp.h" 43 44 static struct spdk_iscsi_init_grp * 45 iscsi_init_grp_create(int tag) 46 { 47 struct spdk_iscsi_init_grp *ig; 48 49 ig = calloc(1, sizeof(*ig)); 50 if (ig == NULL) { 51 SPDK_ERRLOG("calloc() failed for initiator group\n"); 52 return NULL; 53 } 54 55 ig->tag = tag; 56 TAILQ_INIT(&ig->initiator_head); 57 TAILQ_INIT(&ig->netmask_head); 58 return ig; 59 } 60 61 static struct spdk_iscsi_initiator_name * 62 iscsi_init_grp_find_initiator(struct spdk_iscsi_init_grp *ig, char *name) 63 { 64 struct spdk_iscsi_initiator_name *iname; 65 66 TAILQ_FOREACH(iname, &ig->initiator_head, tailq) { 67 if (!strcmp(iname->name, name)) { 68 return iname; 69 } 70 } 71 return NULL; 72 } 73 74 static int 75 iscsi_init_grp_add_initiator(struct spdk_iscsi_init_grp *ig, char *name) 76 { 77 struct spdk_iscsi_initiator_name *iname; 78 char *p; 79 size_t len; 80 81 if (ig->ninitiators >= MAX_INITIATOR) { 82 SPDK_ERRLOG("> MAX_INITIATOR(=%d) is not allowed\n", MAX_INITIATOR); 83 return -EPERM; 84 } 85 86 len = strlen(name); 87 if (len > MAX_INITIATOR_NAME) { 88 SPDK_ERRLOG("Initiator Name is larger than 223 bytes\n"); 89 return -EINVAL; 90 } 91 92 iname = iscsi_init_grp_find_initiator(ig, name); 93 if (iname != NULL) { 94 return -EEXIST; 95 } 96 97 iname = calloc(1, sizeof(*iname)); 98 if (iname == NULL) { 99 SPDK_ERRLOG("malloc() failed for initiator name str\n"); 100 return -ENOMEM; 101 } 102 103 memcpy(iname->name, name, len); 104 105 /* Replace "ALL" by "ANY" if set */ 106 p = strstr(iname->name, "ALL"); 107 if (p != NULL) { 108 SPDK_WARNLOG("Please use \"%s\" instead of \"%s\"\n", "ANY", "ALL"); 109 SPDK_WARNLOG("Converting \"%s\" to \"%s\" automatically\n", "ALL", "ANY"); 110 memcpy(p, "ANY", 3); 111 } 112 113 TAILQ_INSERT_TAIL(&ig->initiator_head, iname, tailq); 114 ig->ninitiators++; 115 116 SPDK_DEBUGLOG(iscsi, "InitiatorName %s\n", name); 117 return 0; 118 } 119 120 static int 121 iscsi_init_grp_delete_initiator(struct spdk_iscsi_init_grp *ig, char *name) 122 { 123 struct spdk_iscsi_initiator_name *iname; 124 125 iname = iscsi_init_grp_find_initiator(ig, name); 126 if (iname == NULL) { 127 return -ENOENT; 128 } 129 130 TAILQ_REMOVE(&ig->initiator_head, iname, tailq); 131 ig->ninitiators--; 132 free(iname); 133 return 0; 134 } 135 136 static int 137 iscsi_init_grp_add_initiators(struct spdk_iscsi_init_grp *ig, int num_inames, 138 char **inames) 139 { 140 int i; 141 int rc; 142 143 for (i = 0; i < num_inames; i++) { 144 rc = iscsi_init_grp_add_initiator(ig, inames[i]); 145 if (rc < 0) { 146 goto cleanup; 147 } 148 } 149 return 0; 150 151 cleanup: 152 for (; i > 0; --i) { 153 iscsi_init_grp_delete_initiator(ig, inames[i - 1]); 154 } 155 return rc; 156 } 157 158 static void 159 iscsi_init_grp_delete_all_initiators(struct spdk_iscsi_init_grp *ig) 160 { 161 struct spdk_iscsi_initiator_name *iname, *tmp; 162 163 TAILQ_FOREACH_SAFE(iname, &ig->initiator_head, tailq, tmp) { 164 TAILQ_REMOVE(&ig->initiator_head, iname, tailq); 165 ig->ninitiators--; 166 free(iname); 167 } 168 } 169 170 static int 171 iscsi_init_grp_delete_initiators(struct spdk_iscsi_init_grp *ig, int num_inames, char **inames) 172 { 173 int i; 174 int rc; 175 176 for (i = 0; i < num_inames; i++) { 177 rc = iscsi_init_grp_delete_initiator(ig, inames[i]); 178 if (rc < 0) { 179 goto cleanup; 180 } 181 } 182 return 0; 183 184 cleanup: 185 for (; i > 0; --i) { 186 rc = iscsi_init_grp_add_initiator(ig, inames[i - 1]); 187 if (rc != 0) { 188 iscsi_init_grp_delete_all_initiators(ig); 189 break; 190 } 191 } 192 return -1; 193 } 194 195 static struct spdk_iscsi_initiator_netmask * 196 iscsi_init_grp_find_netmask(struct spdk_iscsi_init_grp *ig, const char *mask) 197 { 198 struct spdk_iscsi_initiator_netmask *netmask; 199 200 TAILQ_FOREACH(netmask, &ig->netmask_head, tailq) { 201 if (!strcmp(netmask->mask, mask)) { 202 return netmask; 203 } 204 } 205 return NULL; 206 } 207 208 static int 209 iscsi_init_grp_add_netmask(struct spdk_iscsi_init_grp *ig, char *mask) 210 { 211 struct spdk_iscsi_initiator_netmask *imask; 212 char *p; 213 size_t len; 214 215 if (ig->nnetmasks >= MAX_NETMASK) { 216 SPDK_ERRLOG("> MAX_NETMASK(=%d) is not allowed\n", MAX_NETMASK); 217 return -EPERM; 218 } 219 220 len = strlen(mask); 221 if (len > MAX_INITIATOR_ADDR) { 222 SPDK_ERRLOG("Initiator Name is larger than %d bytes\n", MAX_INITIATOR_ADDR); 223 return -EINVAL; 224 } 225 226 imask = iscsi_init_grp_find_netmask(ig, mask); 227 if (imask != NULL) { 228 return -EEXIST; 229 } 230 231 imask = calloc(1, sizeof(*imask)); 232 if (imask == NULL) { 233 SPDK_ERRLOG("malloc() failed for inititator mask str\n"); 234 return -ENOMEM; 235 } 236 237 memcpy(imask->mask, mask, len); 238 239 /* Replace "ALL" by "ANY" if set */ 240 p = strstr(imask->mask, "ALL"); 241 if (p != NULL) { 242 SPDK_WARNLOG("Please use \"%s\" instead of \"%s\"\n", "ANY", "ALL"); 243 SPDK_WARNLOG("Converting \"%s\" to \"%s\" automatically\n", "ALL", "ANY"); 244 memcpy(p, "ANY", 3); 245 } 246 247 TAILQ_INSERT_TAIL(&ig->netmask_head, imask, tailq); 248 ig->nnetmasks++; 249 250 SPDK_DEBUGLOG(iscsi, "Netmask %s\n", mask); 251 return 0; 252 } 253 254 static int 255 iscsi_init_grp_delete_netmask(struct spdk_iscsi_init_grp *ig, char *mask) 256 { 257 struct spdk_iscsi_initiator_netmask *imask; 258 259 imask = iscsi_init_grp_find_netmask(ig, mask); 260 if (imask == NULL) { 261 return -ENOENT; 262 } 263 264 TAILQ_REMOVE(&ig->netmask_head, imask, tailq); 265 ig->nnetmasks--; 266 free(imask); 267 return 0; 268 } 269 270 static int 271 iscsi_init_grp_add_netmasks(struct spdk_iscsi_init_grp *ig, int num_imasks, char **imasks) 272 { 273 int i; 274 int rc; 275 276 for (i = 0; i < num_imasks; i++) { 277 rc = iscsi_init_grp_add_netmask(ig, imasks[i]); 278 if (rc != 0) { 279 goto cleanup; 280 } 281 } 282 return 0; 283 284 cleanup: 285 for (; i > 0; --i) { 286 iscsi_init_grp_delete_netmask(ig, imasks[i - 1]); 287 } 288 return rc; 289 } 290 291 static void 292 iscsi_init_grp_delete_all_netmasks(struct spdk_iscsi_init_grp *ig) 293 { 294 struct spdk_iscsi_initiator_netmask *imask, *tmp; 295 296 TAILQ_FOREACH_SAFE(imask, &ig->netmask_head, tailq, tmp) { 297 TAILQ_REMOVE(&ig->netmask_head, imask, tailq); 298 ig->nnetmasks--; 299 free(imask); 300 } 301 } 302 303 static int 304 iscsi_init_grp_delete_netmasks(struct spdk_iscsi_init_grp *ig, int num_imasks, char **imasks) 305 { 306 int i; 307 int rc; 308 309 for (i = 0; i < num_imasks; i++) { 310 rc = iscsi_init_grp_delete_netmask(ig, imasks[i]); 311 if (rc != 0) { 312 goto cleanup; 313 } 314 } 315 return 0; 316 317 cleanup: 318 for (; i > 0; --i) { 319 rc = iscsi_init_grp_add_netmask(ig, imasks[i - 1]); 320 if (rc != 0) { 321 iscsi_init_grp_delete_all_netmasks(ig); 322 break; 323 } 324 } 325 return -1; 326 } 327 328 int 329 iscsi_init_grp_register(struct spdk_iscsi_init_grp *ig) 330 { 331 struct spdk_iscsi_init_grp *tmp; 332 int rc = -1; 333 334 assert(ig != NULL); 335 336 pthread_mutex_lock(&g_iscsi.mutex); 337 tmp = iscsi_init_grp_find_by_tag(ig->tag); 338 if (tmp == NULL) { 339 TAILQ_INSERT_TAIL(&g_iscsi.ig_head, ig, tailq); 340 rc = 0; 341 } 342 pthread_mutex_unlock(&g_iscsi.mutex); 343 344 return rc; 345 } 346 347 /* 348 * Create initiator group from list of initiator ip/hostnames and netmasks 349 * The initiator hostname/netmask lists are allocated by the caller on the 350 * heap. Freed later by common initiator_group_destroy() code 351 */ 352 int 353 iscsi_init_grp_create_from_initiator_list(int tag, 354 int num_initiator_names, 355 char **initiator_names, 356 int num_initiator_masks, 357 char **initiator_masks) 358 { 359 int rc = -1; 360 struct spdk_iscsi_init_grp *ig = NULL; 361 362 SPDK_DEBUGLOG(iscsi, 363 "add initiator group (from initiator list) tag=%d, #initiators=%d, #masks=%d\n", 364 tag, num_initiator_names, num_initiator_masks); 365 366 ig = iscsi_init_grp_create(tag); 367 if (!ig) { 368 SPDK_ERRLOG("initiator group create error (%d)\n", tag); 369 return rc; 370 } 371 372 rc = iscsi_init_grp_add_initiators(ig, num_initiator_names, 373 initiator_names); 374 if (rc < 0) { 375 SPDK_ERRLOG("add initiator name error\n"); 376 goto cleanup; 377 } 378 379 rc = iscsi_init_grp_add_netmasks(ig, num_initiator_masks, 380 initiator_masks); 381 if (rc < 0) { 382 SPDK_ERRLOG("add initiator netmask error\n"); 383 goto cleanup; 384 } 385 386 rc = iscsi_init_grp_register(ig); 387 if (rc < 0) { 388 SPDK_ERRLOG("initiator group register error (%d)\n", tag); 389 goto cleanup; 390 } 391 return 0; 392 393 cleanup: 394 iscsi_init_grp_destroy(ig); 395 return rc; 396 } 397 398 int 399 iscsi_init_grp_add_initiators_from_initiator_list(int tag, 400 int num_initiator_names, 401 char **initiator_names, 402 int num_initiator_masks, 403 char **initiator_masks) 404 { 405 int rc = -1; 406 struct spdk_iscsi_init_grp *ig; 407 408 SPDK_DEBUGLOG(iscsi, 409 "add initiator to initiator group: tag=%d, #initiators=%d, #masks=%d\n", 410 tag, num_initiator_names, num_initiator_masks); 411 412 pthread_mutex_lock(&g_iscsi.mutex); 413 ig = iscsi_init_grp_find_by_tag(tag); 414 if (!ig) { 415 pthread_mutex_unlock(&g_iscsi.mutex); 416 SPDK_ERRLOG("initiator group (%d) is not found\n", tag); 417 return rc; 418 } 419 420 rc = iscsi_init_grp_add_initiators(ig, num_initiator_names, 421 initiator_names); 422 if (rc < 0) { 423 SPDK_ERRLOG("add initiator name error\n"); 424 goto error; 425 } 426 427 rc = iscsi_init_grp_add_netmasks(ig, num_initiator_masks, 428 initiator_masks); 429 if (rc < 0) { 430 SPDK_ERRLOG("add initiator netmask error\n"); 431 iscsi_init_grp_delete_initiators(ig, num_initiator_names, 432 initiator_names); 433 } 434 435 error: 436 pthread_mutex_unlock(&g_iscsi.mutex); 437 return rc; 438 } 439 440 int 441 iscsi_init_grp_delete_initiators_from_initiator_list(int tag, 442 int num_initiator_names, 443 char **initiator_names, 444 int num_initiator_masks, 445 char **initiator_masks) 446 { 447 int rc = -1; 448 struct spdk_iscsi_init_grp *ig; 449 450 SPDK_DEBUGLOG(iscsi, 451 "delete initiator from initiator group: tag=%d, #initiators=%d, #masks=%d\n", 452 tag, num_initiator_names, num_initiator_masks); 453 454 pthread_mutex_lock(&g_iscsi.mutex); 455 ig = iscsi_init_grp_find_by_tag(tag); 456 if (!ig) { 457 pthread_mutex_unlock(&g_iscsi.mutex); 458 SPDK_ERRLOG("initiator group (%d) is not found\n", tag); 459 return rc; 460 } 461 462 rc = iscsi_init_grp_delete_initiators(ig, num_initiator_names, 463 initiator_names); 464 if (rc < 0) { 465 SPDK_ERRLOG("delete initiator name error\n"); 466 goto error; 467 } 468 469 rc = iscsi_init_grp_delete_netmasks(ig, num_initiator_masks, 470 initiator_masks); 471 if (rc < 0) { 472 SPDK_ERRLOG("delete initiator netmask error\n"); 473 iscsi_init_grp_add_initiators(ig, num_initiator_names, 474 initiator_names); 475 goto error; 476 } 477 478 error: 479 pthread_mutex_unlock(&g_iscsi.mutex); 480 return rc; 481 } 482 483 void 484 iscsi_init_grp_destroy(struct spdk_iscsi_init_grp *ig) 485 { 486 if (!ig) { 487 return; 488 } 489 490 iscsi_init_grp_delete_all_initiators(ig); 491 iscsi_init_grp_delete_all_netmasks(ig); 492 free(ig); 493 }; 494 495 struct spdk_iscsi_init_grp * 496 iscsi_init_grp_find_by_tag(int tag) 497 { 498 struct spdk_iscsi_init_grp *ig; 499 500 TAILQ_FOREACH(ig, &g_iscsi.ig_head, tailq) { 501 if (ig->tag == tag) { 502 return ig; 503 } 504 } 505 506 return NULL; 507 } 508 509 void 510 iscsi_init_grps_destroy(void) 511 { 512 struct spdk_iscsi_init_grp *ig, *tmp; 513 514 SPDK_DEBUGLOG(iscsi, "iscsi_init_grp_array_destroy\n"); 515 pthread_mutex_lock(&g_iscsi.mutex); 516 TAILQ_FOREACH_SAFE(ig, &g_iscsi.ig_head, tailq, tmp) { 517 TAILQ_REMOVE(&g_iscsi.ig_head, ig, tailq); 518 iscsi_init_grp_destroy(ig); 519 } 520 pthread_mutex_unlock(&g_iscsi.mutex); 521 } 522 523 struct spdk_iscsi_init_grp * 524 iscsi_init_grp_unregister(int tag) 525 { 526 struct spdk_iscsi_init_grp *ig; 527 528 pthread_mutex_lock(&g_iscsi.mutex); 529 TAILQ_FOREACH(ig, &g_iscsi.ig_head, tailq) { 530 if (ig->tag == tag) { 531 TAILQ_REMOVE(&g_iscsi.ig_head, ig, tailq); 532 pthread_mutex_unlock(&g_iscsi.mutex); 533 return ig; 534 } 535 } 536 pthread_mutex_unlock(&g_iscsi.mutex); 537 return NULL; 538 } 539 540 static void 541 iscsi_init_grp_info_json(struct spdk_iscsi_init_grp *ig, 542 struct spdk_json_write_ctx *w) 543 { 544 struct spdk_iscsi_initiator_name *iname; 545 struct spdk_iscsi_initiator_netmask *imask; 546 547 spdk_json_write_object_begin(w); 548 549 spdk_json_write_named_int32(w, "tag", ig->tag); 550 551 spdk_json_write_named_array_begin(w, "initiators"); 552 TAILQ_FOREACH(iname, &ig->initiator_head, tailq) { 553 spdk_json_write_string(w, iname->name); 554 } 555 spdk_json_write_array_end(w); 556 557 spdk_json_write_named_array_begin(w, "netmasks"); 558 TAILQ_FOREACH(imask, &ig->netmask_head, tailq) { 559 spdk_json_write_string(w, imask->mask); 560 } 561 spdk_json_write_array_end(w); 562 563 spdk_json_write_object_end(w); 564 } 565 566 static void 567 iscsi_init_grp_config_json(struct spdk_iscsi_init_grp *ig, 568 struct spdk_json_write_ctx *w) 569 { 570 spdk_json_write_object_begin(w); 571 572 spdk_json_write_named_string(w, "method", "iscsi_create_initiator_group"); 573 574 spdk_json_write_name(w, "params"); 575 iscsi_init_grp_info_json(ig, w); 576 577 spdk_json_write_object_end(w); 578 } 579 580 void 581 iscsi_init_grps_info_json(struct spdk_json_write_ctx *w) 582 { 583 struct spdk_iscsi_init_grp *ig; 584 585 TAILQ_FOREACH(ig, &g_iscsi.ig_head, tailq) { 586 iscsi_init_grp_info_json(ig, w); 587 } 588 } 589 590 void 591 iscsi_init_grps_config_json(struct spdk_json_write_ctx *w) 592 { 593 struct spdk_iscsi_init_grp *ig; 594 595 TAILQ_FOREACH(ig, &g_iscsi.ig_head, tailq) { 596 iscsi_init_grp_config_json(ig, w); 597 } 598 } 599