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