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 #include "spdk/env.h" 37 #include "spdk/string.h" 38 #include "spdk/sock.h" 39 #include "spdk/likely.h" 40 41 #include "iscsi/iscsi.h" 42 #include "iscsi/init_grp.h" 43 #include "iscsi/portal_grp.h" 44 #include "iscsi/conn.h" 45 #include "iscsi/task.h" 46 47 #include "spdk_internal/event.h" 48 #include "spdk_internal/log.h" 49 50 struct spdk_iscsi_opts *g_spdk_iscsi_opts = NULL; 51 52 static spdk_iscsi_init_cb g_init_cb_fn = NULL; 53 static void *g_init_cb_arg = NULL; 54 55 static spdk_iscsi_fini_cb g_fini_cb_fn; 56 static void *g_fini_cb_arg; 57 58 #define ISCSI_CONFIG_TMPL \ 59 "[iSCSI]\n" \ 60 " # node name (not include optional part)\n" \ 61 " # Users can optionally change this to fit their environment.\n" \ 62 " NodeBase \"%s\"\n" \ 63 "\n" \ 64 " # files\n" \ 65 " %s %s\n" \ 66 "\n" \ 67 " # socket I/O timeout sec. (polling is infinity)\n" \ 68 " Timeout %d\n" \ 69 "\n" \ 70 " # authentication information for discovery session\n" \ 71 " DiscoveryAuthMethod %s\n" \ 72 " DiscoveryAuthGroup %s\n" \ 73 "\n" \ 74 " MaxSessions %d\n" \ 75 " MaxConnectionsPerSession %d\n" \ 76 " MaxConnections %d\n" \ 77 " MaxQueueDepth %d\n" \ 78 "\n" \ 79 " # iSCSI initial parameters negotiate with initiators\n" \ 80 " # NOTE: incorrect values might crash\n" \ 81 " DefaultTime2Wait %d\n" \ 82 " DefaultTime2Retain %d\n" \ 83 "\n" \ 84 " FirstBurstLength %d\n" \ 85 " ImmediateData %s\n" \ 86 " ErrorRecoveryLevel %d\n" \ 87 "\n" 88 89 static void 90 iscsi_globals_config_text(FILE *fp) 91 { 92 const char *authmethod = "None"; 93 char authgroup[32] = "None"; 94 95 if (NULL == fp) { 96 return; 97 } 98 99 if (g_spdk_iscsi.require_chap) { 100 authmethod = "CHAP"; 101 } else if (g_spdk_iscsi.mutual_chap) { 102 authmethod = "CHAP Mutual"; 103 } else if (!g_spdk_iscsi.disable_chap) { 104 authmethod = "Auto"; 105 } 106 107 if (g_spdk_iscsi.chap_group) { 108 snprintf(authgroup, sizeof(authgroup), "AuthGroup%d", g_spdk_iscsi.chap_group); 109 } 110 111 fprintf(fp, ISCSI_CONFIG_TMPL, 112 g_spdk_iscsi.nodebase, 113 g_spdk_iscsi.authfile ? "AuthFile" : "", 114 g_spdk_iscsi.authfile ? g_spdk_iscsi.authfile : "", 115 g_spdk_iscsi.timeout, authmethod, authgroup, 116 g_spdk_iscsi.MaxSessions, g_spdk_iscsi.MaxConnectionsPerSession, 117 g_spdk_iscsi.MaxConnections, 118 g_spdk_iscsi.MaxQueueDepth, 119 g_spdk_iscsi.DefaultTime2Wait, g_spdk_iscsi.DefaultTime2Retain, 120 g_spdk_iscsi.FirstBurstLength, 121 (g_spdk_iscsi.ImmediateData) ? "Yes" : "No", 122 g_spdk_iscsi.ErrorRecoveryLevel); 123 } 124 125 #define ISCSI_DATA_BUFFER_ALIGNMENT (0x1000) 126 #define ISCSI_DATA_BUFFER_MASK (ISCSI_DATA_BUFFER_ALIGNMENT - 1) 127 128 static void 129 mobj_ctor(struct spdk_mempool *mp, __attribute__((unused)) void *arg, 130 void *_m, __attribute__((unused)) unsigned i) 131 { 132 struct spdk_mobj *m = _m; 133 134 m->mp = mp; 135 m->buf = (uint8_t *)m + sizeof(struct spdk_mobj); 136 m->buf = (void *)((unsigned long)((uint8_t *)m->buf + ISCSI_DATA_BUFFER_ALIGNMENT) & 137 ~ISCSI_DATA_BUFFER_MASK); 138 } 139 140 #define NUM_PDU_PER_CONNECTION(iscsi) (2 * (iscsi->MaxQueueDepth + MAX_LARGE_DATAIN_PER_CONNECTION + 8)) 141 #define PDU_POOL_SIZE(iscsi) (iscsi->MaxConnections * NUM_PDU_PER_CONNECTION(iscsi)) 142 #define IMMEDIATE_DATA_POOL_SIZE(iscsi) (iscsi->MaxConnections * 128) 143 #define DATA_OUT_POOL_SIZE(iscsi) (iscsi->MaxConnections * MAX_DATA_OUT_PER_CONNECTION) 144 145 static int 146 iscsi_initialize_pdu_pool(void) 147 { 148 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 149 int imm_mobj_size = SPDK_BDEV_BUF_SIZE_WITH_MD(spdk_get_max_immediate_data_size()) + 150 sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT; 151 int dout_mobj_size = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) + 152 sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT; 153 154 /* create PDU pool */ 155 iscsi->pdu_pool = spdk_mempool_create("PDU_Pool", 156 PDU_POOL_SIZE(iscsi), 157 sizeof(struct spdk_iscsi_pdu), 158 256, SPDK_ENV_SOCKET_ID_ANY); 159 if (!iscsi->pdu_pool) { 160 SPDK_ERRLOG("create PDU pool failed\n"); 161 return -1; 162 } 163 164 iscsi->pdu_immediate_data_pool = spdk_mempool_create_ctor("PDU_immediate_data_Pool", 165 IMMEDIATE_DATA_POOL_SIZE(iscsi), 166 imm_mobj_size, 256, 167 SPDK_ENV_SOCKET_ID_ANY, 168 mobj_ctor, NULL); 169 if (!iscsi->pdu_immediate_data_pool) { 170 SPDK_ERRLOG("create PDU immediate data pool failed\n"); 171 return -1; 172 } 173 174 iscsi->pdu_data_out_pool = spdk_mempool_create_ctor("PDU_data_out_Pool", 175 DATA_OUT_POOL_SIZE(iscsi), 176 dout_mobj_size, 256, 177 SPDK_ENV_SOCKET_ID_ANY, 178 mobj_ctor, NULL); 179 if (!iscsi->pdu_data_out_pool) { 180 SPDK_ERRLOG("create PDU data out pool failed\n"); 181 return -1; 182 } 183 184 return 0; 185 } 186 187 static void 188 iscsi_sess_ctor(struct spdk_mempool *pool, void *arg, void *session_buf, 189 unsigned index) 190 { 191 struct spdk_iscsi_globals *iscsi = arg; 192 struct spdk_iscsi_sess *sess = session_buf; 193 194 iscsi->session[index] = sess; 195 196 /* tsih 0 is reserved, so start tsih values at 1. */ 197 sess->tsih = index + 1; 198 } 199 200 #define DEFAULT_TASK_POOL_SIZE 32768 201 202 static int 203 iscsi_initialize_task_pool(void) 204 { 205 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 206 207 /* create scsi_task pool */ 208 iscsi->task_pool = spdk_mempool_create("SCSI_TASK_Pool", 209 DEFAULT_TASK_POOL_SIZE, 210 sizeof(struct spdk_iscsi_task), 211 128, SPDK_ENV_SOCKET_ID_ANY); 212 if (!iscsi->task_pool) { 213 SPDK_ERRLOG("create task pool failed\n"); 214 return -1; 215 } 216 217 return 0; 218 } 219 220 #define SESSION_POOL_SIZE(iscsi) (iscsi->MaxSessions) 221 static int 222 iscsi_initialize_session_pool(void) 223 { 224 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 225 226 iscsi->session_pool = spdk_mempool_create_ctor("Session_Pool", 227 SESSION_POOL_SIZE(iscsi), 228 sizeof(struct spdk_iscsi_sess), 0, 229 SPDK_ENV_SOCKET_ID_ANY, 230 iscsi_sess_ctor, iscsi); 231 if (!iscsi->session_pool) { 232 SPDK_ERRLOG("create session pool failed\n"); 233 return -1; 234 } 235 236 return 0; 237 } 238 239 static int 240 iscsi_initialize_all_pools(void) 241 { 242 if (iscsi_initialize_pdu_pool() != 0) { 243 return -1; 244 } 245 246 if (iscsi_initialize_session_pool() != 0) { 247 return -1; 248 } 249 250 if (iscsi_initialize_task_pool() != 0) { 251 return -1; 252 } 253 254 return 0; 255 } 256 257 static void 258 iscsi_check_pool(struct spdk_mempool *pool, size_t count) 259 { 260 if (pool && spdk_mempool_count(pool) != count) { 261 SPDK_ERRLOG("spdk_mempool_count(%s) == %zu, should be %zu\n", 262 spdk_mempool_get_name(pool), spdk_mempool_count(pool), count); 263 } 264 } 265 266 static void 267 iscsi_check_pools(void) 268 { 269 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 270 271 iscsi_check_pool(iscsi->pdu_pool, PDU_POOL_SIZE(iscsi)); 272 iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi)); 273 iscsi_check_pool(iscsi->pdu_immediate_data_pool, IMMEDIATE_DATA_POOL_SIZE(iscsi)); 274 iscsi_check_pool(iscsi->pdu_data_out_pool, DATA_OUT_POOL_SIZE(iscsi)); 275 iscsi_check_pool(iscsi->task_pool, DEFAULT_TASK_POOL_SIZE); 276 } 277 278 static void 279 iscsi_free_pools(void) 280 { 281 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 282 283 spdk_mempool_free(iscsi->pdu_pool); 284 spdk_mempool_free(iscsi->session_pool); 285 spdk_mempool_free(iscsi->pdu_immediate_data_pool); 286 spdk_mempool_free(iscsi->pdu_data_out_pool); 287 spdk_mempool_free(iscsi->task_pool); 288 } 289 290 void spdk_put_pdu(struct spdk_iscsi_pdu *pdu) 291 { 292 if (!pdu) { 293 return; 294 } 295 296 pdu->ref--; 297 298 if (pdu->ref < 0) { 299 SPDK_ERRLOG("Negative PDU refcount: %p\n", pdu); 300 pdu->ref = 0; 301 } 302 303 if (pdu->ref == 0) { 304 if (pdu->mobj) { 305 spdk_mempool_put(pdu->mobj->mp, (void *)pdu->mobj); 306 } 307 308 if (pdu->data && !pdu->data_from_mempool) { 309 free(pdu->data); 310 } 311 312 spdk_mempool_put(g_spdk_iscsi.pdu_pool, (void *)pdu); 313 } 314 } 315 316 struct spdk_iscsi_pdu *spdk_get_pdu(void) 317 { 318 struct spdk_iscsi_pdu *pdu; 319 320 pdu = spdk_mempool_get(g_spdk_iscsi.pdu_pool); 321 if (!pdu) { 322 SPDK_ERRLOG("Unable to get PDU\n"); 323 abort(); 324 } 325 326 /* we do not want to zero out the last part of the structure reserved for AHS and sense data */ 327 memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs)); 328 pdu->ref = 1; 329 330 return pdu; 331 } 332 333 static void 334 iscsi_log_globals(void) 335 { 336 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AuthFile %s\n", 337 g_spdk_iscsi.authfile ? g_spdk_iscsi.authfile : "(none)"); 338 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NodeBase %s\n", g_spdk_iscsi.nodebase); 339 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxSessions %d\n", g_spdk_iscsi.MaxSessions); 340 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxConnectionsPerSession %d\n", 341 g_spdk_iscsi.MaxConnectionsPerSession); 342 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxQueueDepth %d\n", g_spdk_iscsi.MaxQueueDepth); 343 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Wait %d\n", 344 g_spdk_iscsi.DefaultTime2Wait); 345 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Retain %d\n", 346 g_spdk_iscsi.DefaultTime2Retain); 347 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "FirstBurstLength %d\n", 348 g_spdk_iscsi.FirstBurstLength); 349 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ImmediateData %s\n", 350 g_spdk_iscsi.ImmediateData ? "Yes" : "No"); 351 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AllowDuplicateIsid %s\n", 352 g_spdk_iscsi.AllowDuplicateIsid ? "Yes" : "No"); 353 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ErrorRecoveryLevel %d\n", 354 g_spdk_iscsi.ErrorRecoveryLevel); 355 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Timeout %d\n", g_spdk_iscsi.timeout); 356 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NopInInterval %d\n", 357 g_spdk_iscsi.nopininterval); 358 if (g_spdk_iscsi.disable_chap) { 359 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 360 "DiscoveryAuthMethod None\n"); 361 } else if (!g_spdk_iscsi.require_chap) { 362 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 363 "DiscoveryAuthMethod Auto\n"); 364 } else { 365 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 366 "DiscoveryAuthMethod %s %s\n", 367 g_spdk_iscsi.require_chap ? "CHAP" : "", 368 g_spdk_iscsi.mutual_chap ? "Mutual" : ""); 369 } 370 371 if (g_spdk_iscsi.chap_group == 0) { 372 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 373 "DiscoveryAuthGroup None\n"); 374 } else { 375 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 376 "DiscoveryAuthGroup AuthGroup%d\n", 377 g_spdk_iscsi.chap_group); 378 } 379 } 380 381 static void 382 iscsi_opts_init(struct spdk_iscsi_opts *opts) 383 { 384 opts->MaxSessions = DEFAULT_MAX_SESSIONS; 385 opts->MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION; 386 opts->MaxQueueDepth = DEFAULT_MAX_QUEUE_DEPTH; 387 opts->DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT; 388 opts->DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN; 389 opts->FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH; 390 opts->ImmediateData = DEFAULT_IMMEDIATEDATA; 391 opts->AllowDuplicateIsid = false; 392 opts->ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL; 393 opts->timeout = DEFAULT_TIMEOUT; 394 opts->nopininterval = DEFAULT_NOPININTERVAL; 395 opts->disable_chap = false; 396 opts->require_chap = false; 397 opts->mutual_chap = false; 398 opts->chap_group = 0; 399 opts->authfile = NULL; 400 opts->nodebase = NULL; 401 opts->min_connections_per_core = 0; 402 } 403 404 struct spdk_iscsi_opts * 405 spdk_iscsi_opts_alloc(void) 406 { 407 struct spdk_iscsi_opts *opts; 408 409 opts = calloc(1, sizeof(*opts)); 410 if (!opts) { 411 SPDK_ERRLOG("calloc() failed for iscsi options\n"); 412 return NULL; 413 } 414 415 iscsi_opts_init(opts); 416 417 return opts; 418 } 419 420 void 421 spdk_iscsi_opts_free(struct spdk_iscsi_opts *opts) 422 { 423 free(opts->authfile); 424 free(opts->nodebase); 425 free(opts); 426 } 427 428 /* Deep copy of spdk_iscsi_opts */ 429 struct spdk_iscsi_opts * 430 spdk_iscsi_opts_copy(struct spdk_iscsi_opts *src) 431 { 432 struct spdk_iscsi_opts *dst; 433 434 dst = calloc(1, sizeof(*dst)); 435 if (!dst) { 436 SPDK_ERRLOG("calloc() failed for iscsi options\n"); 437 return NULL; 438 } 439 440 if (src->authfile) { 441 dst->authfile = strdup(src->authfile); 442 if (!dst->authfile) { 443 free(dst); 444 SPDK_ERRLOG("failed to strdup for auth file %s\n", src->authfile); 445 return NULL; 446 } 447 } 448 449 if (src->nodebase) { 450 dst->nodebase = strdup(src->nodebase); 451 if (!dst->nodebase) { 452 free(dst->authfile); 453 free(dst); 454 SPDK_ERRLOG("failed to strdup for nodebase %s\n", src->nodebase); 455 return NULL; 456 } 457 } 458 459 dst->MaxSessions = src->MaxSessions; 460 dst->MaxConnectionsPerSession = src->MaxConnectionsPerSession; 461 dst->MaxQueueDepth = src->MaxQueueDepth; 462 dst->DefaultTime2Wait = src->DefaultTime2Wait; 463 dst->DefaultTime2Retain = src->DefaultTime2Retain; 464 dst->FirstBurstLength = src->FirstBurstLength; 465 dst->ImmediateData = src->ImmediateData; 466 dst->AllowDuplicateIsid = src->AllowDuplicateIsid; 467 dst->ErrorRecoveryLevel = src->ErrorRecoveryLevel; 468 dst->timeout = src->timeout; 469 dst->nopininterval = src->nopininterval; 470 dst->disable_chap = src->disable_chap; 471 dst->require_chap = src->require_chap; 472 dst->mutual_chap = src->mutual_chap; 473 dst->chap_group = src->chap_group; 474 dst->min_connections_per_core = 0; 475 476 return dst; 477 } 478 479 static int 480 iscsi_read_config_file_params(struct spdk_conf_section *sp, 481 struct spdk_iscsi_opts *opts) 482 { 483 const char *val; 484 int MaxSessions; 485 int MaxConnectionsPerSession; 486 int MaxQueueDepth; 487 int DefaultTime2Wait; 488 int DefaultTime2Retain; 489 int FirstBurstLength; 490 int ErrorRecoveryLevel; 491 int timeout; 492 int nopininterval; 493 int min_conn_per_core = 0; 494 const char *ag_tag; 495 int ag_tag_i; 496 int i; 497 498 val = spdk_conf_section_get_val(sp, "Comment"); 499 if (val != NULL) { 500 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val); 501 } 502 503 val = spdk_conf_section_get_val(sp, "AuthFile"); 504 if (val != NULL) { 505 opts->authfile = strdup(val); 506 if (!opts->authfile) { 507 SPDK_ERRLOG("strdup() failed for AuthFile\n"); 508 return -ENOMEM; 509 } 510 } 511 512 val = spdk_conf_section_get_val(sp, "NodeBase"); 513 if (val != NULL) { 514 opts->nodebase = strdup(val); 515 if (!opts->nodebase) { 516 free(opts->authfile); 517 SPDK_ERRLOG("strdup() failed for NodeBase\n"); 518 return -ENOMEM; 519 } 520 } 521 522 MaxSessions = spdk_conf_section_get_intval(sp, "MaxSessions"); 523 if (MaxSessions >= 0) { 524 opts->MaxSessions = MaxSessions; 525 } 526 527 MaxConnectionsPerSession = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession"); 528 if (MaxConnectionsPerSession >= 0) { 529 opts->MaxConnectionsPerSession = MaxConnectionsPerSession; 530 } 531 532 MaxQueueDepth = spdk_conf_section_get_intval(sp, "MaxQueueDepth"); 533 if (MaxQueueDepth >= 0) { 534 opts->MaxQueueDepth = MaxQueueDepth; 535 } 536 537 DefaultTime2Wait = spdk_conf_section_get_intval(sp, "DefaultTime2Wait"); 538 if (DefaultTime2Wait >= 0) { 539 opts->DefaultTime2Wait = DefaultTime2Wait; 540 } 541 542 DefaultTime2Retain = spdk_conf_section_get_intval(sp, "DefaultTime2Retain"); 543 if (DefaultTime2Retain >= 0) { 544 opts->DefaultTime2Retain = DefaultTime2Retain; 545 } 546 547 FirstBurstLength = spdk_conf_section_get_intval(sp, "FirstBurstLength"); 548 if (FirstBurstLength >= 0) { 549 opts->FirstBurstLength = FirstBurstLength; 550 } 551 552 opts->ImmediateData = spdk_conf_section_get_boolval(sp, "ImmediateData", 553 opts->ImmediateData); 554 555 /* This option is only for test. 556 * If AllowDuplicateIsid is enabled, it allows different connections carrying 557 * TSIH=0 login the target within the same session. 558 */ 559 opts->AllowDuplicateIsid = spdk_conf_section_get_boolval(sp, "AllowDuplicateIsid", 560 opts->AllowDuplicateIsid); 561 562 ErrorRecoveryLevel = spdk_conf_section_get_intval(sp, "ErrorRecoveryLevel"); 563 if (ErrorRecoveryLevel >= 0) { 564 opts->ErrorRecoveryLevel = ErrorRecoveryLevel; 565 } 566 timeout = spdk_conf_section_get_intval(sp, "Timeout"); 567 if (timeout >= 0) { 568 opts->timeout = timeout; 569 } 570 nopininterval = spdk_conf_section_get_intval(sp, "NopInInterval"); 571 if (nopininterval >= 0) { 572 opts->nopininterval = nopininterval; 573 } 574 val = spdk_conf_section_get_val(sp, "DiscoveryAuthMethod"); 575 if (val != NULL) { 576 for (i = 0; ; i++) { 577 val = spdk_conf_section_get_nmval(sp, "DiscoveryAuthMethod", 0, i); 578 if (val == NULL) { 579 break; 580 } 581 if (strcasecmp(val, "CHAP") == 0) { 582 opts->require_chap = true; 583 } else if (strcasecmp(val, "Mutual") == 0) { 584 opts->require_chap = true; 585 opts->mutual_chap = true; 586 } else if (strcasecmp(val, "Auto") == 0) { 587 opts->disable_chap = false; 588 opts->require_chap = false; 589 opts->mutual_chap = false; 590 } else if (strcasecmp(val, "None") == 0) { 591 opts->disable_chap = true; 592 opts->require_chap = false; 593 opts->mutual_chap = false; 594 } else { 595 SPDK_ERRLOG("unknown CHAP mode %s\n", val); 596 } 597 } 598 if (opts->mutual_chap && !opts->require_chap) { 599 free(opts->authfile); 600 free(opts->nodebase); 601 SPDK_ERRLOG("CHAP must set to be required when using mutual CHAP.\n"); 602 return -EINVAL; 603 } 604 } 605 val = spdk_conf_section_get_val(sp, "DiscoveryAuthGroup"); 606 if (val != NULL) { 607 ag_tag = val; 608 if (strcasecmp(ag_tag, "None") == 0) { 609 opts->chap_group = 0; 610 } else { 611 if (strncasecmp(ag_tag, "AuthGroup", 612 strlen("AuthGroup")) != 0 613 || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1 614 || ag_tag_i == 0) { 615 SPDK_ERRLOG("invalid auth group %s, ignoring\n", ag_tag); 616 } else { 617 opts->chap_group = ag_tag_i; 618 } 619 } 620 } 621 min_conn_per_core = spdk_conf_section_get_intval(sp, "MinConnectionsPerCore"); 622 if (min_conn_per_core >= 0) { 623 SPDK_WARNLOG("MinConnectionsPerCore is deprecated and will be ignored.\n"); 624 } 625 626 return 0; 627 } 628 629 static int 630 iscsi_opts_verify(struct spdk_iscsi_opts *opts) 631 { 632 if (!opts->nodebase) { 633 opts->nodebase = strdup(SPDK_ISCSI_DEFAULT_NODEBASE); 634 if (opts->nodebase == NULL) { 635 SPDK_ERRLOG("strdup() failed for default nodebase\n"); 636 return -ENOMEM; 637 } 638 } 639 640 if (opts->MaxSessions == 0 || opts->MaxSessions > 65535) { 641 SPDK_ERRLOG("%d is invalid. MaxSessions must be more than 0 and no more than 65535\n", 642 opts->MaxSessions); 643 return -EINVAL; 644 } 645 646 if (opts->MaxConnectionsPerSession == 0 || opts->MaxConnectionsPerSession > 65535) { 647 SPDK_ERRLOG("%d is invalid. MaxConnectionsPerSession must be more than 0 and no more than 65535\n", 648 opts->MaxConnectionsPerSession); 649 return -EINVAL; 650 } 651 652 if (opts->MaxQueueDepth == 0 || opts->MaxQueueDepth > 256) { 653 SPDK_ERRLOG("%d is invalid. MaxQueueDepth must be more than 0 and no more than 256\n", 654 opts->MaxQueueDepth); 655 return -EINVAL; 656 } 657 658 if (opts->DefaultTime2Wait > 3600) { 659 SPDK_ERRLOG("%d is invalid. DefaultTime2Wait must be no more than 3600\n", 660 opts->DefaultTime2Wait); 661 return -EINVAL; 662 } 663 664 if (opts->DefaultTime2Retain > 3600) { 665 SPDK_ERRLOG("%d is invalid. DefaultTime2Retain must be no more than 3600\n", 666 opts->DefaultTime2Retain); 667 return -EINVAL; 668 } 669 670 if (opts->FirstBurstLength >= SPDK_ISCSI_MIN_FIRST_BURST_LENGTH) { 671 if (opts->FirstBurstLength > SPDK_ISCSI_MAX_BURST_LENGTH) { 672 SPDK_ERRLOG("FirstBurstLength %d shall not exceed MaxBurstLength %d\n", 673 opts->FirstBurstLength, SPDK_ISCSI_MAX_BURST_LENGTH); 674 return -EINVAL; 675 } 676 } else { 677 SPDK_ERRLOG("FirstBurstLength %d shall be no less than %d\n", 678 opts->FirstBurstLength, SPDK_ISCSI_MIN_FIRST_BURST_LENGTH); 679 return -EINVAL; 680 } 681 682 if (opts->ErrorRecoveryLevel > 2) { 683 SPDK_ERRLOG("ErrorRecoveryLevel %d is not supported.\n", opts->ErrorRecoveryLevel); 684 return -EINVAL; 685 } 686 687 if (opts->timeout < 0) { 688 SPDK_ERRLOG("%d is invalid. timeout must not be less than 0\n", opts->timeout); 689 return -EINVAL; 690 } 691 692 if (opts->nopininterval < 0 || opts->nopininterval > MAX_NOPININTERVAL) { 693 SPDK_ERRLOG("%d is invalid. nopinterval must be between 0 and %d\n", 694 opts->nopininterval, MAX_NOPININTERVAL); 695 return -EINVAL; 696 } 697 698 if (!spdk_iscsi_check_chap_params(opts->disable_chap, opts->require_chap, 699 opts->mutual_chap, opts->chap_group)) { 700 SPDK_ERRLOG("CHAP params in opts are illegal combination\n"); 701 return -EINVAL; 702 } 703 704 return 0; 705 } 706 707 static int 708 iscsi_parse_options(struct spdk_iscsi_opts **popts) 709 { 710 struct spdk_iscsi_opts *opts; 711 struct spdk_conf_section *sp; 712 int rc; 713 714 opts = spdk_iscsi_opts_alloc(); 715 if (!opts) { 716 SPDK_ERRLOG("spdk_iscsi_opts_alloc_failed() failed\n"); 717 return -ENOMEM; 718 } 719 720 /* Process parameters */ 721 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "iscsi_read_config_file_parmas\n"); 722 sp = spdk_conf_find_section(NULL, "iSCSI"); 723 if (sp != NULL) { 724 rc = iscsi_read_config_file_params(sp, opts); 725 if (rc != 0) { 726 free(opts); 727 SPDK_ERRLOG("iscsi_read_config_file_params() failed\n"); 728 return rc; 729 } 730 } 731 732 *popts = opts; 733 734 return 0; 735 } 736 737 static int 738 iscsi_set_global_params(struct spdk_iscsi_opts *opts) 739 { 740 int rc; 741 742 rc = iscsi_opts_verify(opts); 743 if (rc != 0) { 744 SPDK_ERRLOG("spdk_iscsi_opts_verify() failed\n"); 745 return rc; 746 } 747 748 if (opts->authfile != NULL) { 749 g_spdk_iscsi.authfile = strdup(opts->authfile); 750 if (!g_spdk_iscsi.authfile) { 751 SPDK_ERRLOG("failed to strdup for auth file %s\n", opts->authfile); 752 return -ENOMEM; 753 } 754 } 755 756 g_spdk_iscsi.nodebase = strdup(opts->nodebase); 757 if (!g_spdk_iscsi.nodebase) { 758 SPDK_ERRLOG("failed to strdup for nodebase %s\n", opts->nodebase); 759 return -ENOMEM; 760 } 761 762 g_spdk_iscsi.MaxSessions = opts->MaxSessions; 763 g_spdk_iscsi.MaxConnectionsPerSession = opts->MaxConnectionsPerSession; 764 g_spdk_iscsi.MaxQueueDepth = opts->MaxQueueDepth; 765 g_spdk_iscsi.DefaultTime2Wait = opts->DefaultTime2Wait; 766 g_spdk_iscsi.DefaultTime2Retain = opts->DefaultTime2Retain; 767 g_spdk_iscsi.FirstBurstLength = opts->FirstBurstLength; 768 g_spdk_iscsi.ImmediateData = opts->ImmediateData; 769 g_spdk_iscsi.AllowDuplicateIsid = opts->AllowDuplicateIsid; 770 g_spdk_iscsi.ErrorRecoveryLevel = opts->ErrorRecoveryLevel; 771 g_spdk_iscsi.timeout = opts->timeout; 772 g_spdk_iscsi.nopininterval = opts->nopininterval; 773 g_spdk_iscsi.disable_chap = opts->disable_chap; 774 g_spdk_iscsi.require_chap = opts->require_chap; 775 g_spdk_iscsi.mutual_chap = opts->mutual_chap; 776 g_spdk_iscsi.chap_group = opts->chap_group; 777 778 if (opts->min_connections_per_core) { 779 SPDK_WARNLOG("iSCSI option 'min_connections_per_core' has been deprecated and will be ignored.\n"); 780 } 781 782 iscsi_log_globals(); 783 784 return 0; 785 } 786 787 int 788 spdk_iscsi_set_discovery_auth(bool disable_chap, bool require_chap, bool mutual_chap, 789 int32_t chap_group) 790 { 791 if (!spdk_iscsi_check_chap_params(disable_chap, require_chap, mutual_chap, 792 chap_group)) { 793 SPDK_ERRLOG("CHAP params are illegal combination\n"); 794 return -EINVAL; 795 } 796 797 pthread_mutex_lock(&g_spdk_iscsi.mutex); 798 g_spdk_iscsi.disable_chap = disable_chap; 799 g_spdk_iscsi.require_chap = require_chap; 800 g_spdk_iscsi.mutual_chap = mutual_chap; 801 g_spdk_iscsi.chap_group = chap_group; 802 pthread_mutex_unlock(&g_spdk_iscsi.mutex); 803 804 return 0; 805 } 806 807 int 808 spdk_iscsi_auth_group_add_secret(struct spdk_iscsi_auth_group *group, 809 const char *user, const char *secret, 810 const char *muser, const char *msecret) 811 { 812 struct spdk_iscsi_auth_secret *_secret; 813 size_t len; 814 815 if (user == NULL || secret == NULL) { 816 SPDK_ERRLOG("user and secret must be specified\n"); 817 return -EINVAL; 818 } 819 820 if (muser != NULL && msecret == NULL) { 821 SPDK_ERRLOG("msecret must be specified with muser\n"); 822 return -EINVAL; 823 } 824 825 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 826 if (strcmp(_secret->user, user) == 0) { 827 SPDK_ERRLOG("user for secret is duplicated\n"); 828 return -EEXIST; 829 } 830 } 831 832 _secret = calloc(1, sizeof(*_secret)); 833 if (_secret == NULL) { 834 SPDK_ERRLOG("calloc() failed for CHAP secret\n"); 835 return -ENOMEM; 836 } 837 838 len = strnlen(user, sizeof(_secret->user)); 839 if (len > sizeof(_secret->user) - 1) { 840 SPDK_ERRLOG("CHAP user longer than %zu characters: %s\n", 841 sizeof(_secret->user) - 1, user); 842 free(_secret); 843 return -EINVAL; 844 } 845 memcpy(_secret->user, user, len); 846 847 len = strnlen(secret, sizeof(_secret->secret)); 848 if (len > sizeof(_secret->secret) - 1) { 849 SPDK_ERRLOG("CHAP secret longer than %zu characters: %s\n", 850 sizeof(_secret->secret) - 1, secret); 851 free(_secret); 852 return -EINVAL; 853 } 854 memcpy(_secret->secret, secret, len); 855 856 if (muser != NULL) { 857 len = strnlen(muser, sizeof(_secret->muser)); 858 if (len > sizeof(_secret->muser) - 1) { 859 SPDK_ERRLOG("Mutual CHAP user longer than %zu characters: %s\n", 860 sizeof(_secret->muser) - 1, muser); 861 free(_secret); 862 return -EINVAL; 863 } 864 memcpy(_secret->muser, muser, len); 865 866 len = strnlen(msecret, sizeof(_secret->msecret)); 867 if (len > sizeof(_secret->msecret) - 1) { 868 SPDK_ERRLOG("Mutual CHAP secret longer than %zu characters: %s\n", 869 sizeof(_secret->msecret) - 1, msecret); 870 free(_secret); 871 return -EINVAL; 872 } 873 memcpy(_secret->msecret, msecret, len); 874 } 875 876 TAILQ_INSERT_TAIL(&group->secret_head, _secret, tailq); 877 return 0; 878 } 879 880 int 881 spdk_iscsi_auth_group_delete_secret(struct spdk_iscsi_auth_group *group, 882 const char *user) 883 { 884 struct spdk_iscsi_auth_secret *_secret; 885 886 if (user == NULL) { 887 SPDK_ERRLOG("user must be specified\n"); 888 return -EINVAL; 889 } 890 891 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 892 if (strcmp(_secret->user, user) == 0) { 893 break; 894 } 895 } 896 897 if (_secret == NULL) { 898 SPDK_ERRLOG("secret is not found\n"); 899 return -ENODEV; 900 } 901 902 TAILQ_REMOVE(&group->secret_head, _secret, tailq); 903 free(_secret); 904 905 return 0; 906 } 907 908 int 909 spdk_iscsi_add_auth_group(int32_t tag, struct spdk_iscsi_auth_group **_group) 910 { 911 struct spdk_iscsi_auth_group *group; 912 913 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 914 if (group->tag == tag) { 915 SPDK_ERRLOG("Auth group (%d) already exists\n", tag); 916 return -EEXIST; 917 } 918 } 919 920 group = calloc(1, sizeof(*group)); 921 if (group == NULL) { 922 SPDK_ERRLOG("calloc() failed for auth group\n"); 923 return -ENOMEM; 924 } 925 926 TAILQ_INIT(&group->secret_head); 927 group->tag = tag; 928 929 TAILQ_INSERT_TAIL(&g_spdk_iscsi.auth_group_head, group, tailq); 930 931 *_group = group; 932 return 0; 933 } 934 935 void 936 spdk_iscsi_delete_auth_group(struct spdk_iscsi_auth_group *group) 937 { 938 struct spdk_iscsi_auth_secret *_secret, *tmp; 939 940 TAILQ_REMOVE(&g_spdk_iscsi.auth_group_head, group, tailq); 941 942 TAILQ_FOREACH_SAFE(_secret, &group->secret_head, tailq, tmp) { 943 TAILQ_REMOVE(&group->secret_head, _secret, tailq); 944 free(_secret); 945 } 946 free(group); 947 } 948 949 struct spdk_iscsi_auth_group * 950 spdk_iscsi_find_auth_group_by_tag(int32_t tag) 951 { 952 struct spdk_iscsi_auth_group *group; 953 954 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 955 if (group->tag == tag) { 956 return group; 957 } 958 } 959 960 return NULL; 961 } 962 963 static void 964 iscsi_auth_groups_destroy(void) 965 { 966 struct spdk_iscsi_auth_group *group, *tmp; 967 968 TAILQ_FOREACH_SAFE(group, &g_spdk_iscsi.auth_group_head, tailq, tmp) { 969 spdk_iscsi_delete_auth_group(group); 970 } 971 } 972 973 static int 974 iscsi_parse_auth_group(struct spdk_conf_section *sp) 975 { 976 int rc; 977 int i; 978 int tag; 979 const char *val, *user, *secret, *muser, *msecret; 980 struct spdk_iscsi_auth_group *group = NULL; 981 982 val = spdk_conf_section_get_val(sp, "Comment"); 983 if (val != NULL) { 984 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val); 985 } 986 987 tag = spdk_conf_section_get_num(sp); 988 989 rc = spdk_iscsi_add_auth_group(tag, &group); 990 if (rc != 0) { 991 SPDK_ERRLOG("Failed to add auth group\n"); 992 return rc; 993 } 994 995 for (i = 0; ; i++) { 996 val = spdk_conf_section_get_nval(sp, "Auth", i); 997 if (val == NULL) { 998 break; 999 } 1000 1001 user = spdk_conf_section_get_nmval(sp, "Auth", i, 0); 1002 secret = spdk_conf_section_get_nmval(sp, "Auth", i, 1); 1003 muser = spdk_conf_section_get_nmval(sp, "Auth", i, 2); 1004 msecret = spdk_conf_section_get_nmval(sp, "Auth", i, 3); 1005 1006 rc = spdk_iscsi_auth_group_add_secret(group, user, secret, muser, msecret); 1007 if (rc != 0) { 1008 SPDK_ERRLOG("Failed to add secret to auth group\n"); 1009 spdk_iscsi_delete_auth_group(group); 1010 return rc; 1011 } 1012 } 1013 1014 return 0; 1015 } 1016 1017 static int 1018 iscsi_parse_auth_info(void) 1019 { 1020 struct spdk_conf *config; 1021 struct spdk_conf_section *sp; 1022 int rc; 1023 1024 config = spdk_conf_allocate(); 1025 if (!config) { 1026 SPDK_ERRLOG("Failed to allocate config file\n"); 1027 return -ENOMEM; 1028 } 1029 1030 rc = spdk_conf_read(config, g_spdk_iscsi.authfile); 1031 if (rc != 0) { 1032 SPDK_INFOLOG(SPDK_LOG_ISCSI, "Failed to load auth file\n"); 1033 spdk_conf_free(config); 1034 return rc; 1035 } 1036 1037 sp = spdk_conf_first_section(config); 1038 while (sp != NULL) { 1039 if (spdk_conf_section_match_prefix(sp, "AuthGroup")) { 1040 if (spdk_conf_section_get_num(sp) == 0) { 1041 SPDK_ERRLOG("Group 0 is invalid\n"); 1042 iscsi_auth_groups_destroy(); 1043 spdk_conf_free(config); 1044 return -EINVAL; 1045 } 1046 1047 rc = iscsi_parse_auth_group(sp); 1048 if (rc != 0) { 1049 SPDK_ERRLOG("parse_auth_group() failed\n"); 1050 iscsi_auth_groups_destroy(); 1051 spdk_conf_free(config); 1052 return rc; 1053 } 1054 } 1055 sp = spdk_conf_next_section(sp); 1056 } 1057 1058 spdk_conf_free(config); 1059 return 0; 1060 } 1061 1062 static struct spdk_iscsi_auth_secret * 1063 iscsi_find_auth_secret(const char *authuser, int ag_tag) 1064 { 1065 struct spdk_iscsi_auth_group *group; 1066 struct spdk_iscsi_auth_secret *_secret; 1067 1068 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 1069 if (group->tag == ag_tag) { 1070 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 1071 if (strcmp(_secret->user, authuser) == 0) { 1072 return _secret; 1073 } 1074 } 1075 } 1076 } 1077 1078 return NULL; 1079 } 1080 1081 int 1082 spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authuser, 1083 int ag_tag) 1084 { 1085 struct spdk_iscsi_auth_secret *_secret; 1086 1087 if (authuser == NULL) { 1088 return -EINVAL; 1089 } 1090 1091 if (auth->user[0] != '\0') { 1092 memset(auth->user, 0, sizeof(auth->user)); 1093 memset(auth->secret, 0, sizeof(auth->secret)); 1094 memset(auth->muser, 0, sizeof(auth->muser)); 1095 memset(auth->msecret, 0, sizeof(auth->msecret)); 1096 } 1097 1098 pthread_mutex_lock(&g_spdk_iscsi.mutex); 1099 1100 _secret = iscsi_find_auth_secret(authuser, ag_tag); 1101 if (_secret == NULL) { 1102 pthread_mutex_unlock(&g_spdk_iscsi.mutex); 1103 1104 SPDK_ERRLOG("CHAP secret is not found: user:%s, tag:%d\n", 1105 authuser, ag_tag); 1106 return -ENOENT; 1107 } 1108 1109 memcpy(auth->user, _secret->user, sizeof(auth->user)); 1110 memcpy(auth->secret, _secret->secret, sizeof(auth->secret)); 1111 1112 if (_secret->muser[0] != '\0') { 1113 memcpy(auth->muser, _secret->muser, sizeof(auth->muser)); 1114 memcpy(auth->msecret, _secret->msecret, sizeof(auth->msecret)); 1115 } 1116 1117 pthread_mutex_unlock(&g_spdk_iscsi.mutex); 1118 return 0; 1119 } 1120 1121 static int 1122 iscsi_initialize_global_params(void) 1123 { 1124 int rc; 1125 1126 if (!g_spdk_iscsi_opts) { 1127 rc = iscsi_parse_options(&g_spdk_iscsi_opts); 1128 if (rc != 0) { 1129 SPDK_ERRLOG("spdk_iscsi_parse_options() failed\n"); 1130 return rc; 1131 } 1132 } 1133 1134 rc = iscsi_set_global_params(g_spdk_iscsi_opts); 1135 if (rc != 0) { 1136 SPDK_ERRLOG("spdk_iscsi_set_global_params() failed\n"); 1137 } 1138 1139 spdk_iscsi_opts_free(g_spdk_iscsi_opts); 1140 g_spdk_iscsi_opts = NULL; 1141 1142 return rc; 1143 } 1144 1145 static void 1146 iscsi_init_complete(int rc) 1147 { 1148 spdk_iscsi_init_cb cb_fn = g_init_cb_fn; 1149 void *cb_arg = g_init_cb_arg; 1150 1151 g_init_cb_fn = NULL; 1152 g_init_cb_arg = NULL; 1153 1154 cb_fn(cb_arg, rc); 1155 } 1156 1157 static int 1158 iscsi_poll_group_poll(void *ctx) 1159 { 1160 struct spdk_iscsi_poll_group *group = ctx; 1161 struct spdk_iscsi_conn *conn, *tmp; 1162 int rc; 1163 1164 if (spdk_unlikely(STAILQ_EMPTY(&group->connections))) { 1165 return 0; 1166 } 1167 1168 rc = spdk_sock_group_poll(group->sock_group); 1169 if (rc < 0) { 1170 SPDK_ERRLOG("Failed to poll sock_group=%p\n", group->sock_group); 1171 } 1172 1173 STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) { 1174 if (conn->state == ISCSI_CONN_STATE_EXITING) { 1175 spdk_iscsi_conn_destruct(conn); 1176 } 1177 } 1178 1179 return -1; 1180 } 1181 1182 static int 1183 iscsi_poll_group_handle_nop(void *ctx) 1184 { 1185 struct spdk_iscsi_poll_group *group = ctx; 1186 struct spdk_iscsi_conn *conn, *tmp; 1187 1188 STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) { 1189 spdk_iscsi_conn_handle_nop(conn); 1190 } 1191 1192 return -1; 1193 } 1194 1195 static void 1196 iscsi_poll_group_create(void *ctx) 1197 { 1198 struct spdk_iscsi_poll_group *pg; 1199 1200 assert(g_spdk_iscsi.poll_group != NULL); 1201 pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()]; 1202 pg->core = spdk_env_get_current_core(); 1203 1204 STAILQ_INIT(&pg->connections); 1205 pg->sock_group = spdk_sock_group_create(); 1206 assert(pg->sock_group != NULL); 1207 1208 pg->poller = spdk_poller_register(iscsi_poll_group_poll, pg, 0); 1209 /* set the period to 1 sec */ 1210 pg->nop_poller = spdk_poller_register(iscsi_poll_group_handle_nop, pg, 1000000); 1211 } 1212 1213 static void 1214 iscsi_poll_group_destroy(void *ctx) 1215 { 1216 struct spdk_iscsi_poll_group *pg; 1217 1218 assert(g_spdk_iscsi.poll_group != NULL); 1219 pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()]; 1220 assert(pg->poller != NULL); 1221 assert(pg->sock_group != NULL); 1222 1223 spdk_sock_group_close(&pg->sock_group); 1224 spdk_poller_unregister(&pg->poller); 1225 spdk_poller_unregister(&pg->nop_poller); 1226 } 1227 1228 static void 1229 initialize_iscsi_poll_group(spdk_msg_fn cpl) 1230 { 1231 size_t g_num_poll_groups = spdk_env_get_last_core() + 1; 1232 1233 g_spdk_iscsi.poll_group = calloc(g_num_poll_groups, sizeof(struct spdk_iscsi_poll_group)); 1234 if (!g_spdk_iscsi.poll_group) { 1235 SPDK_ERRLOG("Failed to allocated iscsi poll group\n"); 1236 iscsi_init_complete(-1); 1237 return; 1238 } 1239 1240 /* Send a message to each thread and create a poll group */ 1241 spdk_for_each_thread(iscsi_poll_group_create, NULL, cpl); 1242 } 1243 1244 static void 1245 iscsi_parse_configuration(void *ctx) 1246 { 1247 int rc; 1248 1249 rc = spdk_iscsi_parse_portal_grps(); 1250 if (rc < 0) { 1251 SPDK_ERRLOG("spdk_iscsi_parse_portal_grps() failed\n"); 1252 goto end; 1253 } 1254 1255 rc = spdk_iscsi_parse_init_grps(); 1256 if (rc < 0) { 1257 SPDK_ERRLOG("spdk_iscsi_parse_init_grps() failed\n"); 1258 goto end; 1259 } 1260 1261 rc = spdk_iscsi_parse_tgt_nodes(); 1262 if (rc < 0) { 1263 SPDK_ERRLOG("spdk_iscsi_parse_tgt_nodes() failed\n"); 1264 } 1265 1266 if (g_spdk_iscsi.authfile != NULL) { 1267 if (access(g_spdk_iscsi.authfile, R_OK) == 0) { 1268 rc = iscsi_parse_auth_info(); 1269 if (rc < 0) { 1270 SPDK_ERRLOG("spdk_iscsi_parse_auth_info() failed\n"); 1271 } 1272 } else { 1273 SPDK_INFOLOG(SPDK_LOG_ISCSI, "CHAP secret file is not found in the path %s\n", 1274 g_spdk_iscsi.authfile); 1275 } 1276 } 1277 1278 end: 1279 iscsi_init_complete(rc); 1280 } 1281 1282 static int 1283 iscsi_parse_globals(void) 1284 { 1285 int rc; 1286 1287 rc = iscsi_initialize_global_params(); 1288 if (rc != 0) { 1289 SPDK_ERRLOG("spdk_iscsi_initialize_iscsi_global_params() failed\n"); 1290 return rc; 1291 } 1292 1293 g_spdk_iscsi.session = calloc(1, sizeof(void *) * g_spdk_iscsi.MaxSessions); 1294 if (!g_spdk_iscsi.session) { 1295 SPDK_ERRLOG("calloc() failed for session array\n"); 1296 return -1; 1297 } 1298 1299 /* 1300 * For now, just support same number of total connections, rather 1301 * than MaxSessions * MaxConnectionsPerSession. After we add better 1302 * handling for low resource conditions from our various buffer 1303 * pools, we can bump this up to support more connections. 1304 */ 1305 g_spdk_iscsi.MaxConnections = g_spdk_iscsi.MaxSessions; 1306 1307 rc = iscsi_initialize_all_pools(); 1308 if (rc != 0) { 1309 SPDK_ERRLOG("spdk_initialize_all_pools() failed\n"); 1310 free(g_spdk_iscsi.session); 1311 g_spdk_iscsi.session = NULL; 1312 return -1; 1313 } 1314 1315 rc = spdk_initialize_iscsi_conns(); 1316 if (rc < 0) { 1317 SPDK_ERRLOG("spdk_initialize_iscsi_conns() failed\n"); 1318 free(g_spdk_iscsi.session); 1319 g_spdk_iscsi.session = NULL; 1320 return rc; 1321 } 1322 1323 initialize_iscsi_poll_group(iscsi_parse_configuration); 1324 return 0; 1325 } 1326 1327 void 1328 spdk_iscsi_init(spdk_iscsi_init_cb cb_fn, void *cb_arg) 1329 { 1330 int rc; 1331 1332 assert(cb_fn != NULL); 1333 g_init_cb_fn = cb_fn; 1334 g_init_cb_arg = cb_arg; 1335 1336 rc = iscsi_parse_globals(); 1337 if (rc < 0) { 1338 SPDK_ERRLOG("spdk_iscsi_parse_globals() failed\n"); 1339 iscsi_init_complete(-1); 1340 } 1341 1342 /* 1343 * spdk_iscsi_parse_configuration() will be called as the callback to 1344 * spdk_initialize_iscsi_poll_group() and will complete iSCSI 1345 * subsystem initialization. 1346 */ 1347 } 1348 1349 void 1350 spdk_iscsi_fini(spdk_iscsi_fini_cb cb_fn, void *cb_arg) 1351 { 1352 g_fini_cb_fn = cb_fn; 1353 g_fini_cb_arg = cb_arg; 1354 1355 spdk_iscsi_portal_grp_close_all(); 1356 spdk_shutdown_iscsi_conns(); 1357 free(g_spdk_iscsi.session); 1358 } 1359 1360 static void 1361 iscsi_fini_done(void *arg) 1362 { 1363 iscsi_check_pools(); 1364 iscsi_free_pools(); 1365 1366 spdk_iscsi_shutdown_tgt_nodes(); 1367 spdk_iscsi_init_grps_destroy(); 1368 spdk_iscsi_portal_grps_destroy(); 1369 iscsi_auth_groups_destroy(); 1370 free(g_spdk_iscsi.authfile); 1371 free(g_spdk_iscsi.nodebase); 1372 free(g_spdk_iscsi.poll_group); 1373 1374 pthread_mutex_destroy(&g_spdk_iscsi.mutex); 1375 g_fini_cb_fn(g_fini_cb_arg); 1376 } 1377 1378 void 1379 spdk_shutdown_iscsi_conns_done(void) 1380 { 1381 if (g_spdk_iscsi.poll_group) { 1382 spdk_for_each_thread(iscsi_poll_group_destroy, NULL, iscsi_fini_done); 1383 } else { 1384 iscsi_fini_done(NULL); 1385 } 1386 } 1387 1388 void 1389 spdk_iscsi_config_text(FILE *fp) 1390 { 1391 iscsi_globals_config_text(fp); 1392 spdk_iscsi_portal_grps_config_text(fp); 1393 spdk_iscsi_init_grps_config_text(fp); 1394 spdk_iscsi_tgt_nodes_config_text(fp); 1395 } 1396 1397 void 1398 spdk_iscsi_opts_info_json(struct spdk_json_write_ctx *w) 1399 { 1400 spdk_json_write_object_begin(w); 1401 1402 if (g_spdk_iscsi.authfile != NULL) { 1403 spdk_json_write_named_string(w, "auth_file", g_spdk_iscsi.authfile); 1404 } 1405 spdk_json_write_named_string(w, "node_base", g_spdk_iscsi.nodebase); 1406 1407 spdk_json_write_named_uint32(w, "max_sessions", g_spdk_iscsi.MaxSessions); 1408 spdk_json_write_named_uint32(w, "max_connections_per_session", 1409 g_spdk_iscsi.MaxConnectionsPerSession); 1410 1411 spdk_json_write_named_uint32(w, "max_queue_depth", g_spdk_iscsi.MaxQueueDepth); 1412 1413 spdk_json_write_named_uint32(w, "default_time2wait", g_spdk_iscsi.DefaultTime2Wait); 1414 spdk_json_write_named_uint32(w, "default_time2retain", g_spdk_iscsi.DefaultTime2Retain); 1415 1416 spdk_json_write_named_uint32(w, "first_burst_length", g_spdk_iscsi.FirstBurstLength); 1417 1418 spdk_json_write_named_bool(w, "immediate_data", g_spdk_iscsi.ImmediateData); 1419 1420 spdk_json_write_named_bool(w, "allow_duplicated_isid", g_spdk_iscsi.AllowDuplicateIsid); 1421 1422 spdk_json_write_named_uint32(w, "error_recovery_level", g_spdk_iscsi.ErrorRecoveryLevel); 1423 1424 spdk_json_write_named_int32(w, "nop_timeout", g_spdk_iscsi.timeout); 1425 spdk_json_write_named_int32(w, "nop_in_interval", g_spdk_iscsi.nopininterval); 1426 1427 spdk_json_write_named_bool(w, "disable_chap", g_spdk_iscsi.disable_chap); 1428 spdk_json_write_named_bool(w, "require_chap", g_spdk_iscsi.require_chap); 1429 spdk_json_write_named_bool(w, "mutual_chap", g_spdk_iscsi.mutual_chap); 1430 spdk_json_write_named_int32(w, "chap_group", g_spdk_iscsi.chap_group); 1431 1432 spdk_json_write_object_end(w); 1433 } 1434 1435 static void 1436 iscsi_auth_group_info_json(struct spdk_iscsi_auth_group *group, 1437 struct spdk_json_write_ctx *w) 1438 { 1439 struct spdk_iscsi_auth_secret *_secret; 1440 1441 spdk_json_write_object_begin(w); 1442 1443 spdk_json_write_named_int32(w, "tag", group->tag); 1444 1445 spdk_json_write_named_array_begin(w, "secrets"); 1446 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 1447 spdk_json_write_object_begin(w); 1448 1449 spdk_json_write_named_string(w, "user", _secret->user); 1450 spdk_json_write_named_string(w, "secret", _secret->secret); 1451 1452 if (_secret->muser[0] != '\0') { 1453 spdk_json_write_named_string(w, "muser", _secret->muser); 1454 spdk_json_write_named_string(w, "msecret", _secret->msecret); 1455 } 1456 1457 spdk_json_write_object_end(w); 1458 } 1459 spdk_json_write_array_end(w); 1460 1461 spdk_json_write_object_end(w); 1462 } 1463 1464 static void 1465 iscsi_auth_group_config_json(struct spdk_iscsi_auth_group *group, 1466 struct spdk_json_write_ctx *w) 1467 { 1468 spdk_json_write_object_begin(w); 1469 1470 spdk_json_write_named_string(w, "method", "add_iscsi_auth_group"); 1471 1472 spdk_json_write_name(w, "params"); 1473 iscsi_auth_group_info_json(group, w); 1474 1475 spdk_json_write_object_end(w); 1476 } 1477 1478 void 1479 spdk_iscsi_auth_groups_info_json(struct spdk_json_write_ctx *w) 1480 { 1481 struct spdk_iscsi_auth_group *group; 1482 1483 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 1484 iscsi_auth_group_info_json(group, w); 1485 } 1486 } 1487 1488 static void 1489 iscsi_auth_groups_config_json(struct spdk_json_write_ctx *w) 1490 { 1491 struct spdk_iscsi_auth_group *group; 1492 1493 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 1494 iscsi_auth_group_config_json(group, w); 1495 } 1496 } 1497 1498 static void 1499 iscsi_opts_config_json(struct spdk_json_write_ctx *w) 1500 { 1501 spdk_json_write_object_begin(w); 1502 1503 spdk_json_write_named_string(w, "method", "set_iscsi_options"); 1504 1505 spdk_json_write_name(w, "params"); 1506 spdk_iscsi_opts_info_json(w); 1507 1508 spdk_json_write_object_end(w); 1509 } 1510 1511 void 1512 spdk_iscsi_config_json(struct spdk_json_write_ctx *w) 1513 { 1514 spdk_json_write_array_begin(w); 1515 iscsi_opts_config_json(w); 1516 spdk_iscsi_portal_grps_config_json(w); 1517 spdk_iscsi_init_grps_config_json(w); 1518 spdk_iscsi_tgt_nodes_config_json(w); 1519 iscsi_auth_groups_config_json(w); 1520 spdk_json_write_array_end(w); 1521 } 1522 1523 SPDK_LOG_REGISTER_COMPONENT("iscsi", SPDK_LOG_ISCSI) 1524