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 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MinConnectionsPerCore%d\n", 381 spdk_iscsi_conn_get_min_per_core()); 382 } 383 384 static void 385 iscsi_opts_init(struct spdk_iscsi_opts *opts) 386 { 387 opts->MaxSessions = DEFAULT_MAX_SESSIONS; 388 opts->MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION; 389 opts->MaxQueueDepth = DEFAULT_MAX_QUEUE_DEPTH; 390 opts->DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT; 391 opts->DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN; 392 opts->FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH; 393 opts->ImmediateData = DEFAULT_IMMEDIATEDATA; 394 opts->AllowDuplicateIsid = false; 395 opts->ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL; 396 opts->timeout = DEFAULT_TIMEOUT; 397 opts->nopininterval = DEFAULT_NOPININTERVAL; 398 opts->disable_chap = false; 399 opts->require_chap = false; 400 opts->mutual_chap = false; 401 opts->chap_group = 0; 402 opts->authfile = NULL; 403 opts->nodebase = NULL; 404 opts->min_connections_per_core = DEFAULT_CONNECTIONS_PER_LCORE; 405 } 406 407 struct spdk_iscsi_opts * 408 spdk_iscsi_opts_alloc(void) 409 { 410 struct spdk_iscsi_opts *opts; 411 412 opts = calloc(1, sizeof(*opts)); 413 if (!opts) { 414 SPDK_ERRLOG("calloc() failed for iscsi options\n"); 415 return NULL; 416 } 417 418 iscsi_opts_init(opts); 419 420 return opts; 421 } 422 423 void 424 spdk_iscsi_opts_free(struct spdk_iscsi_opts *opts) 425 { 426 free(opts->authfile); 427 free(opts->nodebase); 428 free(opts); 429 } 430 431 /* Deep copy of spdk_iscsi_opts */ 432 struct spdk_iscsi_opts * 433 spdk_iscsi_opts_copy(struct spdk_iscsi_opts *src) 434 { 435 struct spdk_iscsi_opts *dst; 436 437 dst = calloc(1, sizeof(*dst)); 438 if (!dst) { 439 SPDK_ERRLOG("calloc() failed for iscsi options\n"); 440 return NULL; 441 } 442 443 if (src->authfile) { 444 dst->authfile = strdup(src->authfile); 445 if (!dst->authfile) { 446 free(dst); 447 SPDK_ERRLOG("failed to strdup for auth file %s\n", src->authfile); 448 return NULL; 449 } 450 } 451 452 if (src->nodebase) { 453 dst->nodebase = strdup(src->nodebase); 454 if (!dst->nodebase) { 455 free(dst->authfile); 456 free(dst); 457 SPDK_ERRLOG("failed to strdup for nodebase %s\n", src->nodebase); 458 return NULL; 459 } 460 } 461 462 dst->MaxSessions = src->MaxSessions; 463 dst->MaxConnectionsPerSession = src->MaxConnectionsPerSession; 464 dst->MaxQueueDepth = src->MaxQueueDepth; 465 dst->DefaultTime2Wait = src->DefaultTime2Wait; 466 dst->DefaultTime2Retain = src->DefaultTime2Retain; 467 dst->FirstBurstLength = src->FirstBurstLength; 468 dst->ImmediateData = src->ImmediateData; 469 dst->AllowDuplicateIsid = src->AllowDuplicateIsid; 470 dst->ErrorRecoveryLevel = src->ErrorRecoveryLevel; 471 dst->timeout = src->timeout; 472 dst->nopininterval = src->nopininterval; 473 dst->disable_chap = src->disable_chap; 474 dst->require_chap = src->require_chap; 475 dst->mutual_chap = src->mutual_chap; 476 dst->chap_group = src->chap_group; 477 dst->min_connections_per_core = src->min_connections_per_core; 478 479 return dst; 480 } 481 482 static int 483 iscsi_read_config_file_params(struct spdk_conf_section *sp, 484 struct spdk_iscsi_opts *opts) 485 { 486 const char *val; 487 int MaxSessions; 488 int MaxConnectionsPerSession; 489 int MaxQueueDepth; 490 int DefaultTime2Wait; 491 int DefaultTime2Retain; 492 int FirstBurstLength; 493 int ErrorRecoveryLevel; 494 int timeout; 495 int nopininterval; 496 int min_conn_per_core = 0; 497 const char *ag_tag; 498 int ag_tag_i; 499 int i; 500 501 val = spdk_conf_section_get_val(sp, "Comment"); 502 if (val != NULL) { 503 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val); 504 } 505 506 val = spdk_conf_section_get_val(sp, "AuthFile"); 507 if (val != NULL) { 508 opts->authfile = strdup(val); 509 if (!opts->authfile) { 510 SPDK_ERRLOG("strdup() failed for AuthFile\n"); 511 return -ENOMEM; 512 } 513 } 514 515 val = spdk_conf_section_get_val(sp, "NodeBase"); 516 if (val != NULL) { 517 opts->nodebase = strdup(val); 518 if (!opts->nodebase) { 519 free(opts->authfile); 520 SPDK_ERRLOG("strdup() failed for NodeBase\n"); 521 return -ENOMEM; 522 } 523 } 524 525 MaxSessions = spdk_conf_section_get_intval(sp, "MaxSessions"); 526 if (MaxSessions >= 0) { 527 opts->MaxSessions = MaxSessions; 528 } 529 530 MaxConnectionsPerSession = spdk_conf_section_get_intval(sp, "MaxConnectionsPerSession"); 531 if (MaxConnectionsPerSession >= 0) { 532 opts->MaxConnectionsPerSession = MaxConnectionsPerSession; 533 } 534 535 MaxQueueDepth = spdk_conf_section_get_intval(sp, "MaxQueueDepth"); 536 if (MaxQueueDepth >= 0) { 537 opts->MaxQueueDepth = MaxQueueDepth; 538 } 539 540 DefaultTime2Wait = spdk_conf_section_get_intval(sp, "DefaultTime2Wait"); 541 if (DefaultTime2Wait >= 0) { 542 opts->DefaultTime2Wait = DefaultTime2Wait; 543 } 544 545 DefaultTime2Retain = spdk_conf_section_get_intval(sp, "DefaultTime2Retain"); 546 if (DefaultTime2Retain >= 0) { 547 opts->DefaultTime2Retain = DefaultTime2Retain; 548 } 549 550 FirstBurstLength = spdk_conf_section_get_intval(sp, "FirstBurstLength"); 551 if (FirstBurstLength >= 0) { 552 opts->FirstBurstLength = FirstBurstLength; 553 } 554 555 opts->ImmediateData = spdk_conf_section_get_boolval(sp, "ImmediateData", 556 opts->ImmediateData); 557 558 /* This option is only for test. 559 * If AllowDuplicateIsid is enabled, it allows different connections carrying 560 * TSIH=0 login the target within the same session. 561 */ 562 opts->AllowDuplicateIsid = spdk_conf_section_get_boolval(sp, "AllowDuplicateIsid", 563 opts->AllowDuplicateIsid); 564 565 ErrorRecoveryLevel = spdk_conf_section_get_intval(sp, "ErrorRecoveryLevel"); 566 if (ErrorRecoveryLevel >= 0) { 567 opts->ErrorRecoveryLevel = ErrorRecoveryLevel; 568 } 569 timeout = spdk_conf_section_get_intval(sp, "Timeout"); 570 if (timeout >= 0) { 571 opts->timeout = timeout; 572 } 573 nopininterval = spdk_conf_section_get_intval(sp, "NopInInterval"); 574 if (nopininterval >= 0) { 575 opts->nopininterval = nopininterval; 576 } 577 val = spdk_conf_section_get_val(sp, "DiscoveryAuthMethod"); 578 if (val != NULL) { 579 for (i = 0; ; i++) { 580 val = spdk_conf_section_get_nmval(sp, "DiscoveryAuthMethod", 0, i); 581 if (val == NULL) { 582 break; 583 } 584 if (strcasecmp(val, "CHAP") == 0) { 585 opts->require_chap = true; 586 } else if (strcasecmp(val, "Mutual") == 0) { 587 opts->require_chap = true; 588 opts->mutual_chap = true; 589 } else if (strcasecmp(val, "Auto") == 0) { 590 opts->disable_chap = false; 591 opts->require_chap = false; 592 opts->mutual_chap = false; 593 } else if (strcasecmp(val, "None") == 0) { 594 opts->disable_chap = true; 595 opts->require_chap = false; 596 opts->mutual_chap = false; 597 } else { 598 SPDK_ERRLOG("unknown CHAP mode %s\n", val); 599 } 600 } 601 if (opts->mutual_chap && !opts->require_chap) { 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 opts->min_connections_per_core = min_conn_per_core; 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 spdk_iscsi_conn_set_min_per_core(opts->min_connections_per_core); 780 781 iscsi_log_globals(); 782 783 return 0; 784 } 785 786 int 787 spdk_iscsi_set_discovery_auth(bool disable_chap, bool require_chap, bool mutual_chap, 788 int32_t chap_group) 789 { 790 if (!spdk_iscsi_check_chap_params(disable_chap, require_chap, mutual_chap, 791 chap_group)) { 792 SPDK_ERRLOG("CHAP params are illegal combination\n"); 793 return -EINVAL; 794 } 795 796 pthread_mutex_lock(&g_spdk_iscsi.mutex); 797 g_spdk_iscsi.disable_chap = disable_chap; 798 g_spdk_iscsi.require_chap = require_chap; 799 g_spdk_iscsi.mutual_chap = mutual_chap; 800 g_spdk_iscsi.chap_group = chap_group; 801 pthread_mutex_unlock(&g_spdk_iscsi.mutex); 802 803 return 0; 804 } 805 806 int 807 spdk_iscsi_auth_group_add_secret(struct spdk_iscsi_auth_group *group, 808 const char *user, const char *secret, 809 const char *muser, const char *msecret) 810 { 811 struct spdk_iscsi_auth_secret *_secret; 812 size_t len; 813 814 if (user == NULL || secret == NULL) { 815 SPDK_ERRLOG("user and secret must be specified\n"); 816 return -EINVAL; 817 } 818 819 if (muser != NULL && msecret == NULL) { 820 SPDK_ERRLOG("msecret must be specified with muser\n"); 821 return -EINVAL; 822 } 823 824 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 825 if (strcmp(_secret->user, user) == 0) { 826 SPDK_ERRLOG("user for secret is duplicated\n"); 827 return -EEXIST; 828 } 829 } 830 831 _secret = calloc(1, sizeof(*_secret)); 832 if (_secret == NULL) { 833 SPDK_ERRLOG("calloc() failed for CHAP secret\n"); 834 return -ENOMEM; 835 } 836 837 len = strnlen(user, sizeof(_secret->user)); 838 if (len > sizeof(_secret->user) - 1) { 839 SPDK_ERRLOG("CHAP user longer than %zu characters: %s\n", 840 sizeof(_secret->user) - 1, user); 841 free(_secret); 842 return -EINVAL; 843 } 844 memcpy(_secret->user, user, len); 845 846 len = strnlen(secret, sizeof(_secret->secret)); 847 if (len > sizeof(_secret->secret) - 1) { 848 SPDK_ERRLOG("CHAP secret longer than %zu characters: %s\n", 849 sizeof(_secret->secret) - 1, secret); 850 free(_secret); 851 return -EINVAL; 852 } 853 memcpy(_secret->secret, secret, len); 854 855 if (muser != NULL) { 856 len = strnlen(muser, sizeof(_secret->muser)); 857 if (len > sizeof(_secret->muser) - 1) { 858 SPDK_ERRLOG("Mutual CHAP user longer than %zu characters: %s\n", 859 sizeof(_secret->muser) - 1, muser); 860 free(_secret); 861 return -EINVAL; 862 } 863 memcpy(_secret->muser, muser, len); 864 865 len = strnlen(msecret, sizeof(_secret->msecret)); 866 if (len > sizeof(_secret->msecret) - 1) { 867 SPDK_ERRLOG("Mutual CHAP secret longer than %zu characters: %s\n", 868 sizeof(_secret->msecret) - 1, msecret); 869 free(_secret); 870 return -EINVAL; 871 } 872 memcpy(_secret->msecret, msecret, len); 873 } 874 875 TAILQ_INSERT_TAIL(&group->secret_head, _secret, tailq); 876 return 0; 877 } 878 879 int 880 spdk_iscsi_auth_group_delete_secret(struct spdk_iscsi_auth_group *group, 881 const char *user) 882 { 883 struct spdk_iscsi_auth_secret *_secret; 884 885 if (user == NULL) { 886 SPDK_ERRLOG("user must be specified\n"); 887 return -EINVAL; 888 } 889 890 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 891 if (strcmp(_secret->user, user) == 0) { 892 break; 893 } 894 } 895 896 if (_secret == NULL) { 897 SPDK_ERRLOG("secret is not found\n"); 898 return -ENODEV; 899 } 900 901 TAILQ_REMOVE(&group->secret_head, _secret, tailq); 902 free(_secret); 903 904 return 0; 905 } 906 907 int 908 spdk_iscsi_add_auth_group(int32_t tag, struct spdk_iscsi_auth_group **_group) 909 { 910 struct spdk_iscsi_auth_group *group; 911 912 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 913 if (group->tag == tag) { 914 SPDK_ERRLOG("Auth group (%d) already exists\n", tag); 915 return -EEXIST; 916 } 917 } 918 919 group = calloc(1, sizeof(*group)); 920 if (group == NULL) { 921 SPDK_ERRLOG("calloc() failed for auth group\n"); 922 return -ENOMEM; 923 } 924 925 TAILQ_INIT(&group->secret_head); 926 group->tag = tag; 927 928 TAILQ_INSERT_TAIL(&g_spdk_iscsi.auth_group_head, group, tailq); 929 930 *_group = group; 931 return 0; 932 } 933 934 void 935 spdk_iscsi_delete_auth_group(struct spdk_iscsi_auth_group *group) 936 { 937 struct spdk_iscsi_auth_secret *_secret, *tmp; 938 939 TAILQ_REMOVE(&g_spdk_iscsi.auth_group_head, group, tailq); 940 941 TAILQ_FOREACH_SAFE(_secret, &group->secret_head, tailq, tmp) { 942 TAILQ_REMOVE(&group->secret_head, _secret, tailq); 943 free(_secret); 944 } 945 free(group); 946 } 947 948 struct spdk_iscsi_auth_group * 949 spdk_iscsi_find_auth_group_by_tag(int32_t tag) 950 { 951 struct spdk_iscsi_auth_group *group; 952 953 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 954 if (group->tag == tag) { 955 return group; 956 } 957 } 958 959 return NULL; 960 } 961 962 static void 963 iscsi_auth_groups_destroy(void) 964 { 965 struct spdk_iscsi_auth_group *group, *tmp; 966 967 TAILQ_FOREACH_SAFE(group, &g_spdk_iscsi.auth_group_head, tailq, tmp) { 968 spdk_iscsi_delete_auth_group(group); 969 } 970 } 971 972 static int 973 iscsi_parse_auth_group(struct spdk_conf_section *sp) 974 { 975 int rc; 976 int i; 977 int tag; 978 const char *val, *user, *secret, *muser, *msecret; 979 struct spdk_iscsi_auth_group *group = NULL; 980 981 val = spdk_conf_section_get_val(sp, "Comment"); 982 if (val != NULL) { 983 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val); 984 } 985 986 tag = spdk_conf_section_get_num(sp); 987 988 rc = spdk_iscsi_add_auth_group(tag, &group); 989 if (rc != 0) { 990 SPDK_ERRLOG("Failed to add auth group\n"); 991 return rc; 992 } 993 994 for (i = 0; ; i++) { 995 val = spdk_conf_section_get_nval(sp, "Auth", i); 996 if (val == NULL) { 997 break; 998 } 999 1000 user = spdk_conf_section_get_nmval(sp, "Auth", i, 0); 1001 secret = spdk_conf_section_get_nmval(sp, "Auth", i, 1); 1002 muser = spdk_conf_section_get_nmval(sp, "Auth", i, 2); 1003 msecret = spdk_conf_section_get_nmval(sp, "Auth", i, 3); 1004 1005 rc = spdk_iscsi_auth_group_add_secret(group, user, secret, muser, msecret); 1006 if (rc != 0) { 1007 SPDK_ERRLOG("Failed to add secret to auth group\n"); 1008 spdk_iscsi_delete_auth_group(group); 1009 return rc; 1010 } 1011 } 1012 1013 return 0; 1014 } 1015 1016 static int 1017 iscsi_parse_auth_info(void) 1018 { 1019 struct spdk_conf *config; 1020 struct spdk_conf_section *sp; 1021 int rc; 1022 1023 config = spdk_conf_allocate(); 1024 if (!config) { 1025 SPDK_ERRLOG("Failed to allocate config file\n"); 1026 return -ENOMEM; 1027 } 1028 1029 rc = spdk_conf_read(config, g_spdk_iscsi.authfile); 1030 if (rc != 0) { 1031 SPDK_INFOLOG(SPDK_LOG_ISCSI, "Failed to load auth file\n"); 1032 spdk_conf_free(config); 1033 return rc; 1034 } 1035 1036 sp = spdk_conf_first_section(config); 1037 while (sp != NULL) { 1038 if (spdk_conf_section_match_prefix(sp, "AuthGroup")) { 1039 if (spdk_conf_section_get_num(sp) == 0) { 1040 SPDK_ERRLOG("Group 0 is invalid\n"); 1041 iscsi_auth_groups_destroy(); 1042 spdk_conf_free(config); 1043 return -EINVAL; 1044 } 1045 1046 rc = iscsi_parse_auth_group(sp); 1047 if (rc != 0) { 1048 SPDK_ERRLOG("parse_auth_group() failed\n"); 1049 iscsi_auth_groups_destroy(); 1050 spdk_conf_free(config); 1051 return rc; 1052 } 1053 } 1054 sp = spdk_conf_next_section(sp); 1055 } 1056 1057 spdk_conf_free(config); 1058 return 0; 1059 } 1060 1061 static struct spdk_iscsi_auth_secret * 1062 iscsi_find_auth_secret(const char *authuser, int ag_tag) 1063 { 1064 struct spdk_iscsi_auth_group *group; 1065 struct spdk_iscsi_auth_secret *_secret; 1066 1067 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 1068 if (group->tag == ag_tag) { 1069 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 1070 if (strcmp(_secret->user, authuser) == 0) { 1071 return _secret; 1072 } 1073 } 1074 } 1075 } 1076 1077 return NULL; 1078 } 1079 1080 int 1081 spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authuser, 1082 int ag_tag) 1083 { 1084 struct spdk_iscsi_auth_secret *_secret; 1085 1086 if (authuser == NULL) { 1087 return -EINVAL; 1088 } 1089 1090 if (auth->user[0] != '\0') { 1091 memset(auth->user, 0, sizeof(auth->user)); 1092 memset(auth->secret, 0, sizeof(auth->secret)); 1093 memset(auth->muser, 0, sizeof(auth->muser)); 1094 memset(auth->msecret, 0, sizeof(auth->msecret)); 1095 } 1096 1097 pthread_mutex_lock(&g_spdk_iscsi.mutex); 1098 1099 _secret = iscsi_find_auth_secret(authuser, ag_tag); 1100 if (_secret == NULL) { 1101 pthread_mutex_unlock(&g_spdk_iscsi.mutex); 1102 1103 SPDK_ERRLOG("CHAP secret is not found: user:%s, tag:%d\n", 1104 authuser, ag_tag); 1105 return -ENOENT; 1106 } 1107 1108 memcpy(auth->user, _secret->user, sizeof(auth->user)); 1109 memcpy(auth->secret, _secret->secret, sizeof(auth->secret)); 1110 1111 if (_secret->muser[0] != '\0') { 1112 memcpy(auth->muser, _secret->muser, sizeof(auth->muser)); 1113 memcpy(auth->msecret, _secret->msecret, sizeof(auth->msecret)); 1114 } 1115 1116 pthread_mutex_unlock(&g_spdk_iscsi.mutex); 1117 return 0; 1118 } 1119 1120 static int 1121 iscsi_initialize_global_params(void) 1122 { 1123 int rc; 1124 1125 if (!g_spdk_iscsi_opts) { 1126 rc = iscsi_parse_options(&g_spdk_iscsi_opts); 1127 if (rc != 0) { 1128 SPDK_ERRLOG("spdk_iscsi_parse_options() failed\n"); 1129 return rc; 1130 } 1131 } 1132 1133 rc = iscsi_set_global_params(g_spdk_iscsi_opts); 1134 if (rc != 0) { 1135 SPDK_ERRLOG("spdk_iscsi_set_global_params() failed\n"); 1136 } 1137 1138 spdk_iscsi_opts_free(g_spdk_iscsi_opts); 1139 g_spdk_iscsi_opts = NULL; 1140 1141 return rc; 1142 } 1143 1144 static void 1145 iscsi_init_complete(int rc) 1146 { 1147 spdk_iscsi_init_cb cb_fn = g_init_cb_fn; 1148 void *cb_arg = g_init_cb_arg; 1149 1150 g_init_cb_fn = NULL; 1151 g_init_cb_arg = NULL; 1152 1153 cb_fn(cb_arg, rc); 1154 } 1155 1156 static int 1157 iscsi_poll_group_poll(void *ctx) 1158 { 1159 struct spdk_iscsi_poll_group *group = ctx; 1160 struct spdk_iscsi_conn *conn, *tmp; 1161 int rc; 1162 1163 if (spdk_unlikely(STAILQ_EMPTY(&group->connections))) { 1164 return 0; 1165 } 1166 1167 rc = spdk_sock_group_poll(group->sock_group); 1168 if (rc < 0) { 1169 SPDK_ERRLOG("Failed to poll sock_group=%p\n", group->sock_group); 1170 } 1171 1172 STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) { 1173 if (conn->state == ISCSI_CONN_STATE_EXITING) { 1174 spdk_iscsi_conn_destruct(conn); 1175 } 1176 } 1177 1178 return -1; 1179 } 1180 1181 static int 1182 iscsi_poll_group_handle_nop(void *ctx) 1183 { 1184 struct spdk_iscsi_poll_group *group = ctx; 1185 struct spdk_iscsi_conn *conn, *tmp; 1186 1187 STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) { 1188 spdk_iscsi_conn_handle_nop(conn); 1189 } 1190 1191 return -1; 1192 } 1193 1194 static void 1195 iscsi_create_poll_group(void *ctx) 1196 { 1197 struct spdk_iscsi_poll_group *pg; 1198 1199 assert(g_spdk_iscsi.poll_group != NULL); 1200 pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()]; 1201 pg->core = spdk_env_get_current_core(); 1202 1203 STAILQ_INIT(&pg->connections); 1204 pg->sock_group = spdk_sock_group_create(); 1205 assert(pg->sock_group != NULL); 1206 1207 pg->poller = spdk_poller_register(iscsi_poll_group_poll, pg, 0); 1208 /* set the period to 1 sec */ 1209 pg->nop_poller = spdk_poller_register(iscsi_poll_group_handle_nop, pg, 1000000); 1210 } 1211 1212 static void 1213 iscsi_unregister_poll_group(void *ctx) 1214 { 1215 struct spdk_iscsi_poll_group *pg; 1216 1217 assert(g_spdk_iscsi.poll_group != NULL); 1218 pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()]; 1219 assert(pg->poller != NULL); 1220 assert(pg->sock_group != NULL); 1221 1222 spdk_sock_group_close(&pg->sock_group); 1223 spdk_poller_unregister(&pg->poller); 1224 spdk_poller_unregister(&pg->nop_poller); 1225 } 1226 1227 static void 1228 initialize_iscsi_poll_group(spdk_msg_fn cpl) 1229 { 1230 size_t g_num_poll_groups = spdk_env_get_last_core() + 1; 1231 1232 g_spdk_iscsi.poll_group = calloc(g_num_poll_groups, sizeof(struct spdk_iscsi_poll_group)); 1233 if (!g_spdk_iscsi.poll_group) { 1234 SPDK_ERRLOG("Failed to allocated iscsi poll group\n"); 1235 iscsi_init_complete(-1); 1236 return; 1237 } 1238 1239 /* Send a message to each thread and create a poll group */ 1240 spdk_for_each_thread(iscsi_create_poll_group, NULL, cpl); 1241 } 1242 1243 static void 1244 iscsi_parse_configuration(void *ctx) 1245 { 1246 int rc; 1247 1248 rc = spdk_iscsi_parse_portal_grps(); 1249 if (rc < 0) { 1250 SPDK_ERRLOG("spdk_iscsi_parse_portal_grps() failed\n"); 1251 goto end; 1252 } 1253 1254 rc = spdk_iscsi_parse_init_grps(); 1255 if (rc < 0) { 1256 SPDK_ERRLOG("spdk_iscsi_parse_init_grps() failed\n"); 1257 goto end; 1258 } 1259 1260 rc = spdk_iscsi_parse_tgt_nodes(); 1261 if (rc < 0) { 1262 SPDK_ERRLOG("spdk_iscsi_parse_tgt_nodes() failed\n"); 1263 } 1264 1265 if (g_spdk_iscsi.authfile != NULL) { 1266 if (access(g_spdk_iscsi.authfile, R_OK) == 0) { 1267 rc = iscsi_parse_auth_info(); 1268 if (rc < 0) { 1269 SPDK_ERRLOG("spdk_iscsi_parse_auth_info() failed\n"); 1270 } 1271 } else { 1272 SPDK_INFOLOG(SPDK_LOG_ISCSI, "CHAP secret file is not found in the path %s\n", 1273 g_spdk_iscsi.authfile); 1274 } 1275 } 1276 1277 end: 1278 iscsi_init_complete(rc); 1279 } 1280 1281 static int 1282 iscsi_parse_globals(void) 1283 { 1284 int rc; 1285 1286 rc = iscsi_initialize_global_params(); 1287 if (rc != 0) { 1288 SPDK_ERRLOG("spdk_iscsi_initialize_iscsi_global_params() failed\n"); 1289 return rc; 1290 } 1291 1292 g_spdk_iscsi.session = spdk_dma_zmalloc(sizeof(void *) * g_spdk_iscsi.MaxSessions, 0, NULL); 1293 if (!g_spdk_iscsi.session) { 1294 SPDK_ERRLOG("spdk_dma_zmalloc() failed for session array\n"); 1295 return -1; 1296 } 1297 1298 /* 1299 * For now, just support same number of total connections, rather 1300 * than MaxSessions * MaxConnectionsPerSession. After we add better 1301 * handling for low resource conditions from our various buffer 1302 * pools, we can bump this up to support more connections. 1303 */ 1304 g_spdk_iscsi.MaxConnections = g_spdk_iscsi.MaxSessions; 1305 1306 rc = iscsi_initialize_all_pools(); 1307 if (rc != 0) { 1308 SPDK_ERRLOG("spdk_initialize_all_pools() failed\n"); 1309 return -1; 1310 } 1311 1312 rc = spdk_initialize_iscsi_conns(); 1313 if (rc < 0) { 1314 SPDK_ERRLOG("spdk_initialize_iscsi_conns() failed\n"); 1315 return rc; 1316 } 1317 1318 initialize_iscsi_poll_group(iscsi_parse_configuration); 1319 return 0; 1320 } 1321 1322 void 1323 spdk_iscsi_init(spdk_iscsi_init_cb cb_fn, void *cb_arg) 1324 { 1325 int rc; 1326 1327 assert(cb_fn != NULL); 1328 g_init_cb_fn = cb_fn; 1329 g_init_cb_arg = cb_arg; 1330 1331 rc = iscsi_parse_globals(); 1332 if (rc < 0) { 1333 SPDK_ERRLOG("spdk_iscsi_parse_globals() failed\n"); 1334 iscsi_init_complete(-1); 1335 } 1336 1337 /* 1338 * spdk_iscsi_parse_configuration() will be called as the callback to 1339 * spdk_initialize_iscsi_poll_group() and will complete iSCSI 1340 * subsystem initialization. 1341 */ 1342 } 1343 1344 void 1345 spdk_iscsi_fini(spdk_iscsi_fini_cb cb_fn, void *cb_arg) 1346 { 1347 g_fini_cb_fn = cb_fn; 1348 g_fini_cb_arg = cb_arg; 1349 1350 spdk_iscsi_portal_grp_close_all(); 1351 spdk_shutdown_iscsi_conns(); 1352 } 1353 1354 static void 1355 iscsi_fini_done(void *arg) 1356 { 1357 iscsi_check_pools(); 1358 iscsi_free_pools(); 1359 1360 spdk_iscsi_shutdown_tgt_nodes(); 1361 spdk_iscsi_init_grps_destroy(); 1362 spdk_iscsi_portal_grps_destroy(); 1363 iscsi_auth_groups_destroy(); 1364 free(g_spdk_iscsi.authfile); 1365 free(g_spdk_iscsi.nodebase); 1366 free(g_spdk_iscsi.poll_group); 1367 1368 pthread_mutex_destroy(&g_spdk_iscsi.mutex); 1369 g_fini_cb_fn(g_fini_cb_arg); 1370 } 1371 1372 void 1373 spdk_shutdown_iscsi_conns_done(void) 1374 { 1375 if (g_spdk_iscsi.poll_group) { 1376 spdk_for_each_thread(iscsi_unregister_poll_group, NULL, iscsi_fini_done); 1377 } else { 1378 iscsi_fini_done(NULL); 1379 } 1380 } 1381 1382 void 1383 spdk_iscsi_config_text(FILE *fp) 1384 { 1385 iscsi_globals_config_text(fp); 1386 spdk_iscsi_portal_grps_config_text(fp); 1387 spdk_iscsi_init_grps_config_text(fp); 1388 spdk_iscsi_tgt_nodes_config_text(fp); 1389 } 1390 1391 void 1392 spdk_iscsi_opts_info_json(struct spdk_json_write_ctx *w) 1393 { 1394 spdk_json_write_object_begin(w); 1395 1396 if (g_spdk_iscsi.authfile != NULL) { 1397 spdk_json_write_named_string(w, "auth_file", g_spdk_iscsi.authfile); 1398 } 1399 spdk_json_write_named_string(w, "node_base", g_spdk_iscsi.nodebase); 1400 1401 spdk_json_write_named_uint32(w, "max_sessions", g_spdk_iscsi.MaxSessions); 1402 spdk_json_write_named_uint32(w, "max_connections_per_session", 1403 g_spdk_iscsi.MaxConnectionsPerSession); 1404 1405 spdk_json_write_named_uint32(w, "max_queue_depth", g_spdk_iscsi.MaxQueueDepth); 1406 1407 spdk_json_write_named_uint32(w, "default_time2wait", g_spdk_iscsi.DefaultTime2Wait); 1408 spdk_json_write_named_uint32(w, "default_time2retain", g_spdk_iscsi.DefaultTime2Retain); 1409 1410 spdk_json_write_named_uint32(w, "first_burst_length", g_spdk_iscsi.FirstBurstLength); 1411 1412 spdk_json_write_named_bool(w, "immediate_data", g_spdk_iscsi.ImmediateData); 1413 1414 spdk_json_write_named_bool(w, "allow_duplicated_isid", g_spdk_iscsi.AllowDuplicateIsid); 1415 1416 spdk_json_write_named_uint32(w, "error_recovery_level", g_spdk_iscsi.ErrorRecoveryLevel); 1417 1418 spdk_json_write_named_int32(w, "nop_timeout", g_spdk_iscsi.timeout); 1419 spdk_json_write_named_int32(w, "nop_in_interval", g_spdk_iscsi.nopininterval); 1420 1421 spdk_json_write_named_bool(w, "disable_chap", g_spdk_iscsi.disable_chap); 1422 spdk_json_write_named_bool(w, "require_chap", g_spdk_iscsi.require_chap); 1423 spdk_json_write_named_bool(w, "mutual_chap", g_spdk_iscsi.mutual_chap); 1424 spdk_json_write_named_int32(w, "chap_group", g_spdk_iscsi.chap_group); 1425 1426 spdk_json_write_named_uint32(w, "min_connections_per_core", 1427 spdk_iscsi_conn_get_min_per_core()); 1428 1429 spdk_json_write_object_end(w); 1430 } 1431 1432 static void 1433 iscsi_auth_group_info_json(struct spdk_iscsi_auth_group *group, 1434 struct spdk_json_write_ctx *w) 1435 { 1436 struct spdk_iscsi_auth_secret *_secret; 1437 1438 spdk_json_write_object_begin(w); 1439 1440 spdk_json_write_named_int32(w, "tag", group->tag); 1441 1442 spdk_json_write_named_array_begin(w, "secrets"); 1443 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 1444 spdk_json_write_object_begin(w); 1445 1446 spdk_json_write_named_string(w, "user", _secret->user); 1447 spdk_json_write_named_string(w, "secret", _secret->secret); 1448 1449 if (_secret->muser[0] != '\0') { 1450 spdk_json_write_named_string(w, "muser", _secret->muser); 1451 spdk_json_write_named_string(w, "msecret", _secret->msecret); 1452 } 1453 1454 spdk_json_write_object_end(w); 1455 } 1456 spdk_json_write_array_end(w); 1457 1458 spdk_json_write_object_end(w); 1459 } 1460 1461 static void 1462 iscsi_auth_group_config_json(struct spdk_iscsi_auth_group *group, 1463 struct spdk_json_write_ctx *w) 1464 { 1465 spdk_json_write_object_begin(w); 1466 1467 spdk_json_write_named_string(w, "method", "add_iscsi_auth_group"); 1468 1469 spdk_json_write_name(w, "params"); 1470 iscsi_auth_group_info_json(group, w); 1471 1472 spdk_json_write_object_end(w); 1473 } 1474 1475 void 1476 spdk_iscsi_auth_groups_info_json(struct spdk_json_write_ctx *w) 1477 { 1478 struct spdk_iscsi_auth_group *group; 1479 1480 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 1481 iscsi_auth_group_info_json(group, w); 1482 } 1483 } 1484 1485 static void 1486 iscsi_auth_groups_config_json(struct spdk_json_write_ctx *w) 1487 { 1488 struct spdk_iscsi_auth_group *group; 1489 1490 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 1491 iscsi_auth_group_config_json(group, w); 1492 } 1493 } 1494 1495 static void 1496 iscsi_opts_config_json(struct spdk_json_write_ctx *w) 1497 { 1498 spdk_json_write_object_begin(w); 1499 1500 spdk_json_write_named_string(w, "method", "set_iscsi_options"); 1501 1502 spdk_json_write_name(w, "params"); 1503 spdk_iscsi_opts_info_json(w); 1504 1505 spdk_json_write_object_end(w); 1506 } 1507 1508 void 1509 spdk_iscsi_config_json(struct spdk_json_write_ctx *w) 1510 { 1511 spdk_json_write_array_begin(w); 1512 iscsi_opts_config_json(w); 1513 spdk_iscsi_portal_grps_config_json(w); 1514 spdk_iscsi_init_grps_config_json(w); 1515 spdk_iscsi_tgt_nodes_config_json(w); 1516 iscsi_auth_groups_config_json(w); 1517 spdk_json_write_array_end(w); 1518 } 1519 1520 SPDK_LOG_REGISTER_COMPONENT("iscsi", SPDK_LOG_ISCSI) 1521