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 spdk_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 spdk_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 spdk_iscsi_initialize_pdu_pool(void) 146 { 147 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 148 int imm_mobj_size = spdk_get_immediate_data_buffer_size() + 149 sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT; 150 int dout_mobj_size = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH + 151 sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT; 152 153 /* create PDU pool */ 154 iscsi->pdu_pool = spdk_mempool_create("PDU_Pool", 155 PDU_POOL_SIZE(iscsi), 156 sizeof(struct spdk_iscsi_pdu), 157 256, SPDK_ENV_SOCKET_ID_ANY); 158 if (!iscsi->pdu_pool) { 159 SPDK_ERRLOG("create PDU pool failed\n"); 160 return -1; 161 } 162 163 iscsi->pdu_immediate_data_pool = spdk_mempool_create_ctor("PDU_immediate_data_Pool", 164 IMMEDIATE_DATA_POOL_SIZE(iscsi), 165 imm_mobj_size, 256, 166 spdk_env_get_socket_id(spdk_env_get_current_core()), 167 spdk_mobj_ctor, NULL); 168 if (!iscsi->pdu_immediate_data_pool) { 169 SPDK_ERRLOG("create PDU immediate data pool failed\n"); 170 return -1; 171 } 172 173 iscsi->pdu_data_out_pool = spdk_mempool_create_ctor("PDU_data_out_Pool", 174 DATA_OUT_POOL_SIZE(iscsi), 175 dout_mobj_size, 256, 176 spdk_env_get_socket_id(spdk_env_get_current_core()), 177 spdk_mobj_ctor, NULL); 178 if (!iscsi->pdu_data_out_pool) { 179 SPDK_ERRLOG("create PDU data out pool failed\n"); 180 return -1; 181 } 182 183 return 0; 184 } 185 186 static void spdk_iscsi_sess_ctor(struct spdk_mempool *pool, void *arg, 187 void *session_buf, unsigned index) 188 { 189 struct spdk_iscsi_globals *iscsi = arg; 190 struct spdk_iscsi_sess *sess = session_buf; 191 192 iscsi->session[index] = sess; 193 194 /* tsih 0 is reserved, so start tsih values at 1. */ 195 sess->tsih = index + 1; 196 } 197 198 #define DEFAULT_TASK_POOL_SIZE 32768 199 200 static int 201 spdk_iscsi_initialize_task_pool(void) 202 { 203 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 204 205 /* create scsi_task pool */ 206 iscsi->task_pool = spdk_mempool_create("SCSI_TASK_Pool", 207 DEFAULT_TASK_POOL_SIZE, 208 sizeof(struct spdk_iscsi_task), 209 128, SPDK_ENV_SOCKET_ID_ANY); 210 if (!iscsi->task_pool) { 211 SPDK_ERRLOG("create task pool failed\n"); 212 return -1; 213 } 214 215 return 0; 216 } 217 218 #define SESSION_POOL_SIZE(iscsi) (iscsi->MaxSessions) 219 static int spdk_iscsi_initialize_session_pool(void) 220 { 221 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 222 223 iscsi->session_pool = spdk_mempool_create_ctor("Session_Pool", 224 SESSION_POOL_SIZE(iscsi), 225 sizeof(struct spdk_iscsi_sess), 0, 226 SPDK_ENV_SOCKET_ID_ANY, 227 spdk_iscsi_sess_ctor, iscsi); 228 if (!iscsi->session_pool) { 229 SPDK_ERRLOG("create session pool failed\n"); 230 return -1; 231 } 232 233 return 0; 234 } 235 236 static int 237 spdk_iscsi_initialize_all_pools(void) 238 { 239 if (spdk_iscsi_initialize_pdu_pool() != 0) { 240 return -1; 241 } 242 243 if (spdk_iscsi_initialize_session_pool() != 0) { 244 return -1; 245 } 246 247 if (spdk_iscsi_initialize_task_pool() != 0) { 248 return -1; 249 } 250 251 return 0; 252 } 253 254 static void 255 spdk_iscsi_check_pool(struct spdk_mempool *pool, size_t count) 256 { 257 if (spdk_mempool_count(pool) != count) { 258 SPDK_ERRLOG("spdk_mempool_count(%s) == %zu, should be %zu\n", 259 spdk_mempool_get_name(pool), spdk_mempool_count(pool), count); 260 } 261 } 262 263 static void 264 spdk_iscsi_check_pools(void) 265 { 266 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 267 268 spdk_iscsi_check_pool(iscsi->pdu_pool, PDU_POOL_SIZE(iscsi)); 269 spdk_iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi)); 270 spdk_iscsi_check_pool(iscsi->pdu_immediate_data_pool, IMMEDIATE_DATA_POOL_SIZE(iscsi)); 271 spdk_iscsi_check_pool(iscsi->pdu_data_out_pool, DATA_OUT_POOL_SIZE(iscsi)); 272 spdk_iscsi_check_pool(iscsi->task_pool, DEFAULT_TASK_POOL_SIZE); 273 } 274 275 static void 276 spdk_iscsi_free_pools(void) 277 { 278 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 279 280 spdk_mempool_free(iscsi->pdu_pool); 281 spdk_mempool_free(iscsi->session_pool); 282 spdk_mempool_free(iscsi->pdu_immediate_data_pool); 283 spdk_mempool_free(iscsi->pdu_data_out_pool); 284 spdk_mempool_free(iscsi->task_pool); 285 } 286 287 void spdk_put_pdu(struct spdk_iscsi_pdu *pdu) 288 { 289 if (!pdu) { 290 return; 291 } 292 293 pdu->ref--; 294 295 if (pdu->ref < 0) { 296 SPDK_ERRLOG("Negative PDU refcount: %p\n", pdu); 297 pdu->ref = 0; 298 } 299 300 if (pdu->ref == 0) { 301 if (pdu->mobj) { 302 spdk_mempool_put(pdu->mobj->mp, (void *)pdu->mobj); 303 } 304 305 if (pdu->data && !pdu->data_from_mempool) { 306 free(pdu->data); 307 } 308 309 spdk_mempool_put(g_spdk_iscsi.pdu_pool, (void *)pdu); 310 } 311 } 312 313 struct spdk_iscsi_pdu *spdk_get_pdu(void) 314 { 315 struct spdk_iscsi_pdu *pdu; 316 317 pdu = spdk_mempool_get(g_spdk_iscsi.pdu_pool); 318 if (!pdu) { 319 SPDK_ERRLOG("Unable to get PDU\n"); 320 abort(); 321 } 322 323 /* we do not want to zero out the last part of the structure reserved for AHS and sense data */ 324 memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs)); 325 pdu->ref = 1; 326 327 return pdu; 328 } 329 330 static void 331 spdk_iscsi_log_globals(void) 332 { 333 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AuthFile %s\n", 334 g_spdk_iscsi.authfile ? g_spdk_iscsi.authfile : "(none)"); 335 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NodeBase %s\n", g_spdk_iscsi.nodebase); 336 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxSessions %d\n", g_spdk_iscsi.MaxSessions); 337 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxConnectionsPerSession %d\n", 338 g_spdk_iscsi.MaxConnectionsPerSession); 339 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MaxQueueDepth %d\n", g_spdk_iscsi.MaxQueueDepth); 340 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Wait %d\n", 341 g_spdk_iscsi.DefaultTime2Wait); 342 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "DefaultTime2Retain %d\n", 343 g_spdk_iscsi.DefaultTime2Retain); 344 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "FirstBurstLength %d\n", 345 g_spdk_iscsi.FirstBurstLength); 346 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ImmediateData %s\n", 347 g_spdk_iscsi.ImmediateData ? "Yes" : "No"); 348 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "AllowDuplicateIsid %s\n", 349 g_spdk_iscsi.AllowDuplicateIsid ? "Yes" : "No"); 350 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "ErrorRecoveryLevel %d\n", 351 g_spdk_iscsi.ErrorRecoveryLevel); 352 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Timeout %d\n", g_spdk_iscsi.timeout); 353 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "NopInInterval %d\n", 354 g_spdk_iscsi.nopininterval); 355 if (g_spdk_iscsi.disable_chap) { 356 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 357 "DiscoveryAuthMethod None\n"); 358 } else if (!g_spdk_iscsi.require_chap) { 359 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 360 "DiscoveryAuthMethod Auto\n"); 361 } else { 362 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 363 "DiscoveryAuthMethod %s %s\n", 364 g_spdk_iscsi.require_chap ? "CHAP" : "", 365 g_spdk_iscsi.mutual_chap ? "Mutual" : ""); 366 } 367 368 if (g_spdk_iscsi.chap_group == 0) { 369 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 370 "DiscoveryAuthGroup None\n"); 371 } else { 372 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 373 "DiscoveryAuthGroup AuthGroup%d\n", 374 g_spdk_iscsi.chap_group); 375 } 376 377 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "MinConnectionsPerCore%d\n", 378 spdk_iscsi_conn_get_min_per_core()); 379 } 380 381 static void 382 spdk_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 = DEFAULT_CONNECTIONS_PER_LCORE; 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 spdk_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 = src->min_connections_per_core; 475 476 return dst; 477 } 478 479 static int 480 spdk_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 SPDK_ERRLOG("CHAP must set to be required when using mutual CHAP.\n"); 600 return -EINVAL; 601 } 602 } 603 val = spdk_conf_section_get_val(sp, "DiscoveryAuthGroup"); 604 if (val != NULL) { 605 ag_tag = val; 606 if (strcasecmp(ag_tag, "None") == 0) { 607 opts->chap_group = 0; 608 } else { 609 if (strncasecmp(ag_tag, "AuthGroup", 610 strlen("AuthGroup")) != 0 611 || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1 612 || ag_tag_i == 0) { 613 SPDK_ERRLOG("invalid auth group %s, ignoring\n", ag_tag); 614 } else { 615 opts->chap_group = ag_tag_i; 616 } 617 } 618 } 619 min_conn_per_core = spdk_conf_section_get_intval(sp, "MinConnectionsPerCore"); 620 if (min_conn_per_core >= 0) { 621 opts->min_connections_per_core = min_conn_per_core; 622 } 623 624 return 0; 625 } 626 627 static int 628 spdk_iscsi_opts_verify(struct spdk_iscsi_opts *opts) 629 { 630 if (!opts->nodebase) { 631 opts->nodebase = strdup(SPDK_ISCSI_DEFAULT_NODEBASE); 632 if (opts->nodebase == NULL) { 633 SPDK_ERRLOG("strdup() failed for default nodebase\n"); 634 return -ENOMEM; 635 } 636 } 637 638 if (opts->MaxSessions == 0 || opts->MaxSessions > 65535) { 639 SPDK_ERRLOG("%d is invalid. MaxSessions must be more than 0 and no more than 65535\n", 640 opts->MaxSessions); 641 return -EINVAL; 642 } 643 644 if (opts->MaxConnectionsPerSession == 0 || opts->MaxConnectionsPerSession > 65535) { 645 SPDK_ERRLOG("%d is invalid. MaxConnectionsPerSession must be more than 0 and no more than 65535\n", 646 opts->MaxConnectionsPerSession); 647 return -EINVAL; 648 } 649 650 if (opts->MaxQueueDepth == 0 || opts->MaxQueueDepth > 256) { 651 SPDK_ERRLOG("%d is invalid. MaxQueueDepth must be more than 0 and no more than 256\n", 652 opts->MaxQueueDepth); 653 return -EINVAL; 654 } 655 656 if (opts->DefaultTime2Wait > 3600) { 657 SPDK_ERRLOG("%d is invalid. DefaultTime2Wait must be no more than 3600\n", 658 opts->DefaultTime2Wait); 659 return -EINVAL; 660 } 661 662 if (opts->DefaultTime2Retain > 3600) { 663 SPDK_ERRLOG("%d is invalid. DefaultTime2Retain must be no more than 3600\n", 664 opts->DefaultTime2Retain); 665 return -EINVAL; 666 } 667 668 if (opts->FirstBurstLength >= SPDK_ISCSI_MIN_FIRST_BURST_LENGTH) { 669 if (opts->FirstBurstLength > SPDK_ISCSI_MAX_BURST_LENGTH) { 670 SPDK_ERRLOG("FirstBurstLength %d shall not exceed MaxBurstLength %d\n", 671 opts->FirstBurstLength, SPDK_ISCSI_MAX_BURST_LENGTH); 672 return -EINVAL; 673 } 674 } else { 675 SPDK_ERRLOG("FirstBurstLength %d shall be no less than %d\n", 676 opts->FirstBurstLength, SPDK_ISCSI_MIN_FIRST_BURST_LENGTH); 677 return -EINVAL; 678 } 679 680 if (opts->ErrorRecoveryLevel > 2) { 681 SPDK_ERRLOG("ErrorRecoveryLevel %d is not supported.\n", opts->ErrorRecoveryLevel); 682 return -EINVAL; 683 } 684 685 if (opts->timeout < 0) { 686 SPDK_ERRLOG("%d is invalid. timeout must not be less than 0\n", opts->timeout); 687 return -EINVAL; 688 } 689 690 if (opts->nopininterval < 0 || opts->nopininterval > MAX_NOPININTERVAL) { 691 SPDK_ERRLOG("%d is invalid. nopinterval must be between 0 and %d\n", 692 opts->nopininterval, MAX_NOPININTERVAL); 693 return -EINVAL; 694 } 695 696 if (!spdk_iscsi_check_chap_params(opts->disable_chap, opts->require_chap, 697 opts->mutual_chap, opts->chap_group)) { 698 SPDK_ERRLOG("CHAP params in opts are illegal combination\n"); 699 return -EINVAL; 700 } 701 702 return 0; 703 } 704 705 static int 706 spdk_iscsi_parse_options(struct spdk_iscsi_opts **popts) 707 { 708 struct spdk_iscsi_opts *opts; 709 struct spdk_conf_section *sp; 710 int rc; 711 712 opts = spdk_iscsi_opts_alloc(); 713 if (!opts) { 714 SPDK_ERRLOG("spdk_iscsi_opts_alloc_failed() failed\n"); 715 return -ENOMEM; 716 } 717 718 /* Process parameters */ 719 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "spdk_iscsi_read_config_file_parmas\n"); 720 sp = spdk_conf_find_section(NULL, "iSCSI"); 721 if (sp != NULL) { 722 rc = spdk_iscsi_read_config_file_params(sp, opts); 723 if (rc != 0) { 724 free(opts); 725 SPDK_ERRLOG("spdk_iscsi_read_config_file_params() failed\n"); 726 return rc; 727 } 728 } 729 730 *popts = opts; 731 732 return 0; 733 } 734 735 static int 736 spdk_iscsi_set_global_params(struct spdk_iscsi_opts *opts) 737 { 738 int rc; 739 740 rc = spdk_iscsi_opts_verify(opts); 741 if (rc != 0) { 742 SPDK_ERRLOG("spdk_iscsi_opts_verify() failed\n"); 743 return rc; 744 } 745 746 if (opts->authfile != NULL) { 747 g_spdk_iscsi.authfile = strdup(opts->authfile); 748 if (!g_spdk_iscsi.authfile) { 749 SPDK_ERRLOG("failed to strdup for auth file %s\n", opts->authfile); 750 return -ENOMEM; 751 } 752 } 753 754 g_spdk_iscsi.nodebase = strdup(opts->nodebase); 755 if (!g_spdk_iscsi.nodebase) { 756 SPDK_ERRLOG("failed to strdup for nodebase %s\n", opts->nodebase); 757 return -ENOMEM; 758 } 759 760 g_spdk_iscsi.MaxSessions = opts->MaxSessions; 761 g_spdk_iscsi.MaxConnectionsPerSession = opts->MaxConnectionsPerSession; 762 g_spdk_iscsi.MaxQueueDepth = opts->MaxQueueDepth; 763 g_spdk_iscsi.DefaultTime2Wait = opts->DefaultTime2Wait; 764 g_spdk_iscsi.DefaultTime2Retain = opts->DefaultTime2Retain; 765 g_spdk_iscsi.FirstBurstLength = opts->FirstBurstLength; 766 g_spdk_iscsi.ImmediateData = opts->ImmediateData; 767 g_spdk_iscsi.AllowDuplicateIsid = opts->AllowDuplicateIsid; 768 g_spdk_iscsi.ErrorRecoveryLevel = opts->ErrorRecoveryLevel; 769 g_spdk_iscsi.timeout = opts->timeout; 770 g_spdk_iscsi.nopininterval = opts->nopininterval; 771 g_spdk_iscsi.disable_chap = opts->disable_chap; 772 g_spdk_iscsi.require_chap = opts->require_chap; 773 g_spdk_iscsi.mutual_chap = opts->mutual_chap; 774 g_spdk_iscsi.chap_group = opts->chap_group; 775 776 spdk_iscsi_conn_set_min_per_core(opts->min_connections_per_core); 777 778 spdk_iscsi_log_globals(); 779 780 return 0; 781 } 782 783 int 784 spdk_iscsi_set_discovery_auth(bool disable_chap, bool require_chap, bool mutual_chap, 785 int32_t chap_group) 786 { 787 if (!spdk_iscsi_check_chap_params(disable_chap, require_chap, mutual_chap, 788 chap_group)) { 789 SPDK_ERRLOG("CHAP params are illegal combination\n"); 790 return -EINVAL; 791 } 792 793 pthread_mutex_lock(&g_spdk_iscsi.mutex); 794 g_spdk_iscsi.disable_chap = disable_chap; 795 g_spdk_iscsi.require_chap = require_chap; 796 g_spdk_iscsi.mutual_chap = mutual_chap; 797 g_spdk_iscsi.chap_group = chap_group; 798 pthread_mutex_unlock(&g_spdk_iscsi.mutex); 799 800 return 0; 801 } 802 803 int 804 spdk_iscsi_auth_group_add_secret(struct spdk_iscsi_auth_group *group, 805 const char *user, const char *secret, 806 const char *muser, const char *msecret) 807 { 808 struct spdk_iscsi_auth_secret *_secret; 809 size_t len; 810 811 if (user == NULL || secret == NULL) { 812 SPDK_ERRLOG("user and secret must be specified\n"); 813 return -EINVAL; 814 } 815 816 if (muser != NULL && msecret == NULL) { 817 SPDK_ERRLOG("msecret must be specified with muser\n"); 818 return -EINVAL; 819 } 820 821 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 822 if (strcmp(_secret->user, user) == 0) { 823 SPDK_ERRLOG("user for secret is duplicated\n"); 824 return -EEXIST; 825 } 826 } 827 828 _secret = calloc(1, sizeof(*_secret)); 829 if (_secret == NULL) { 830 SPDK_ERRLOG("calloc() failed for CHAP secret\n"); 831 return -ENOMEM; 832 } 833 834 len = strnlen(user, sizeof(_secret->user)); 835 if (len > sizeof(_secret->user) - 1) { 836 SPDK_ERRLOG("CHAP user longer than %zu characters: %s\n", 837 sizeof(_secret->user) - 1, user); 838 free(_secret); 839 return -EINVAL; 840 } 841 memcpy(_secret->user, user, len); 842 843 len = strnlen(secret, sizeof(_secret->secret)); 844 if (len > sizeof(_secret->secret) - 1) { 845 SPDK_ERRLOG("CHAP secret longer than %zu characters: %s\n", 846 sizeof(_secret->secret) - 1, secret); 847 free(_secret); 848 return -EINVAL; 849 } 850 memcpy(_secret->secret, secret, len); 851 852 if (muser != NULL) { 853 len = strnlen(muser, sizeof(_secret->muser)); 854 if (len > sizeof(_secret->muser) - 1) { 855 SPDK_ERRLOG("Mutual CHAP user longer than %zu characters: %s\n", 856 sizeof(_secret->muser) - 1, muser); 857 free(_secret); 858 return -EINVAL; 859 } 860 memcpy(_secret->muser, muser, len); 861 862 len = strnlen(msecret, sizeof(_secret->msecret)); 863 if (len > sizeof(_secret->msecret) - 1) { 864 SPDK_ERRLOG("Mutual CHAP secret longer than %zu characters: %s\n", 865 sizeof(_secret->msecret) - 1, msecret); 866 free(_secret); 867 return -EINVAL; 868 } 869 memcpy(_secret->msecret, msecret, len); 870 } 871 872 TAILQ_INSERT_TAIL(&group->secret_head, _secret, tailq); 873 return 0; 874 } 875 876 int 877 spdk_iscsi_auth_group_delete_secret(struct spdk_iscsi_auth_group *group, 878 const char *user) 879 { 880 struct spdk_iscsi_auth_secret *_secret; 881 882 if (user == NULL) { 883 SPDK_ERRLOG("user must be specified\n"); 884 return -EINVAL; 885 } 886 887 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 888 if (strcmp(_secret->user, user) == 0) { 889 break; 890 } 891 } 892 893 if (_secret == NULL) { 894 SPDK_ERRLOG("secret is not found\n"); 895 return -ENODEV; 896 } 897 898 TAILQ_REMOVE(&group->secret_head, _secret, tailq); 899 free(_secret); 900 901 return 0; 902 } 903 904 int 905 spdk_iscsi_add_auth_group(int32_t tag, struct spdk_iscsi_auth_group **_group) 906 { 907 struct spdk_iscsi_auth_group *group; 908 909 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 910 if (group->tag == tag) { 911 SPDK_ERRLOG("Auth group (%d) already exists\n", tag); 912 return -EEXIST; 913 } 914 } 915 916 group = calloc(1, sizeof(*group)); 917 if (group == NULL) { 918 SPDK_ERRLOG("calloc() failed for auth group\n"); 919 return -ENOMEM; 920 } 921 922 TAILQ_INIT(&group->secret_head); 923 group->tag = tag; 924 925 TAILQ_INSERT_TAIL(&g_spdk_iscsi.auth_group_head, group, tailq); 926 927 *_group = group; 928 return 0; 929 } 930 931 void 932 spdk_iscsi_delete_auth_group(struct spdk_iscsi_auth_group *group) 933 { 934 struct spdk_iscsi_auth_secret *_secret, *tmp; 935 936 TAILQ_REMOVE(&g_spdk_iscsi.auth_group_head, group, tailq); 937 938 TAILQ_FOREACH_SAFE(_secret, &group->secret_head, tailq, tmp) { 939 TAILQ_REMOVE(&group->secret_head, _secret, tailq); 940 free(_secret); 941 } 942 free(group); 943 } 944 945 struct spdk_iscsi_auth_group * 946 spdk_iscsi_find_auth_group_by_tag(int32_t tag) 947 { 948 struct spdk_iscsi_auth_group *group; 949 950 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 951 if (group->tag == tag) { 952 return group; 953 } 954 } 955 956 return NULL; 957 } 958 959 static void 960 spdk_iscsi_auth_groups_destroy(void) 961 { 962 struct spdk_iscsi_auth_group *group, *tmp; 963 964 TAILQ_FOREACH_SAFE(group, &g_spdk_iscsi.auth_group_head, tailq, tmp) { 965 spdk_iscsi_delete_auth_group(group); 966 } 967 } 968 969 static int 970 spdk_iscsi_parse_auth_group(struct spdk_conf_section *sp) 971 { 972 int rc; 973 int i; 974 int tag; 975 const char *val, *user, *secret, *muser, *msecret; 976 struct spdk_iscsi_auth_group *group = NULL; 977 978 val = spdk_conf_section_get_val(sp, "Comment"); 979 if (val != NULL) { 980 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Comment %s\n", val); 981 } 982 983 tag = spdk_conf_section_get_num(sp); 984 985 rc = spdk_iscsi_add_auth_group(tag, &group); 986 if (rc != 0) { 987 SPDK_ERRLOG("Failed to add auth group\n"); 988 return rc; 989 } 990 991 for (i = 0; ; i++) { 992 val = spdk_conf_section_get_nval(sp, "Auth", i); 993 if (val == NULL) { 994 break; 995 } 996 997 user = spdk_conf_section_get_nmval(sp, "Auth", i, 0); 998 secret = spdk_conf_section_get_nmval(sp, "Auth", i, 1); 999 muser = spdk_conf_section_get_nmval(sp, "Auth", i, 2); 1000 msecret = spdk_conf_section_get_nmval(sp, "Auth", i, 3); 1001 1002 rc = spdk_iscsi_auth_group_add_secret(group, user, secret, muser, msecret); 1003 if (rc != 0) { 1004 SPDK_ERRLOG("Failed to add secret to auth group\n"); 1005 spdk_iscsi_delete_auth_group(group); 1006 return rc; 1007 } 1008 } 1009 1010 return 0; 1011 } 1012 1013 static int 1014 spdk_iscsi_parse_auth_info(void) 1015 { 1016 struct spdk_conf *config; 1017 struct spdk_conf_section *sp; 1018 int rc; 1019 1020 config = spdk_conf_allocate(); 1021 if (!config) { 1022 SPDK_ERRLOG("Failed to allocate config file\n"); 1023 return -ENOMEM; 1024 } 1025 1026 rc = spdk_conf_read(config, g_spdk_iscsi.authfile); 1027 if (rc != 0) { 1028 SPDK_INFOLOG(SPDK_LOG_ISCSI, "Failed to load auth file\n"); 1029 spdk_conf_free(config); 1030 return rc; 1031 } 1032 1033 sp = spdk_conf_first_section(config); 1034 while (sp != NULL) { 1035 if (spdk_conf_section_match_prefix(sp, "AuthGroup")) { 1036 if (spdk_conf_section_get_num(sp) == 0) { 1037 SPDK_ERRLOG("Group 0 is invalid\n"); 1038 spdk_iscsi_auth_groups_destroy(); 1039 spdk_conf_free(config); 1040 return -EINVAL; 1041 } 1042 1043 rc = spdk_iscsi_parse_auth_group(sp); 1044 if (rc != 0) { 1045 SPDK_ERRLOG("parse_auth_group() failed\n"); 1046 spdk_iscsi_auth_groups_destroy(); 1047 spdk_conf_free(config); 1048 return rc; 1049 } 1050 } 1051 sp = spdk_conf_next_section(sp); 1052 } 1053 1054 spdk_conf_free(config); 1055 return 0; 1056 } 1057 1058 static struct spdk_iscsi_auth_secret * 1059 spdk_iscsi_find_auth_secret(const char *authuser, int ag_tag) 1060 { 1061 struct spdk_iscsi_auth_group *group; 1062 struct spdk_iscsi_auth_secret *_secret; 1063 1064 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 1065 if (group->tag == ag_tag) { 1066 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 1067 if (strcmp(_secret->user, authuser) == 0) { 1068 return _secret; 1069 } 1070 } 1071 } 1072 } 1073 1074 return NULL; 1075 } 1076 1077 int 1078 spdk_iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authuser, 1079 int ag_tag) 1080 { 1081 struct spdk_iscsi_auth_secret *_secret; 1082 1083 if (authuser == NULL) { 1084 return -EINVAL; 1085 } 1086 1087 if (auth->user[0] != '\0') { 1088 memset(auth->user, 0, sizeof(auth->user)); 1089 memset(auth->secret, 0, sizeof(auth->secret)); 1090 memset(auth->muser, 0, sizeof(auth->muser)); 1091 memset(auth->msecret, 0, sizeof(auth->msecret)); 1092 } 1093 1094 pthread_mutex_lock(&g_spdk_iscsi.mutex); 1095 1096 _secret = spdk_iscsi_find_auth_secret(authuser, ag_tag); 1097 if (_secret == NULL) { 1098 pthread_mutex_unlock(&g_spdk_iscsi.mutex); 1099 1100 SPDK_ERRLOG("CHAP secret is not found: user:%s, tag:%d\n", 1101 authuser, ag_tag); 1102 return -ENOENT; 1103 } 1104 1105 memcpy(auth->user, _secret->user, sizeof(auth->user)); 1106 memcpy(auth->secret, _secret->secret, sizeof(auth->secret)); 1107 1108 if (_secret->muser[0] != '\0') { 1109 memcpy(auth->muser, _secret->muser, sizeof(auth->muser)); 1110 memcpy(auth->msecret, _secret->msecret, sizeof(auth->msecret)); 1111 } 1112 1113 pthread_mutex_unlock(&g_spdk_iscsi.mutex); 1114 return 0; 1115 } 1116 1117 static int 1118 spdk_iscsi_initialize_global_params(void) 1119 { 1120 int rc; 1121 1122 if (!g_spdk_iscsi_opts) { 1123 rc = spdk_iscsi_parse_options(&g_spdk_iscsi_opts); 1124 if (rc != 0) { 1125 SPDK_ERRLOG("spdk_iscsi_parse_options() failed\n"); 1126 return rc; 1127 } 1128 } 1129 1130 rc = spdk_iscsi_set_global_params(g_spdk_iscsi_opts); 1131 if (rc != 0) { 1132 SPDK_ERRLOG("spdk_iscsi_set_global_params() failed\n"); 1133 } 1134 1135 spdk_iscsi_opts_free(g_spdk_iscsi_opts); 1136 g_spdk_iscsi_opts = NULL; 1137 1138 return rc; 1139 } 1140 1141 static void 1142 spdk_iscsi_init_complete(int rc) 1143 { 1144 spdk_iscsi_init_cb cb_fn = g_init_cb_fn; 1145 void *cb_arg = g_init_cb_arg; 1146 1147 g_init_cb_fn = NULL; 1148 g_init_cb_arg = NULL; 1149 1150 cb_fn(cb_arg, rc); 1151 } 1152 1153 static int 1154 spdk_iscsi_poll_group_poll(void *ctx) 1155 { 1156 struct spdk_iscsi_poll_group *group = ctx; 1157 struct spdk_iscsi_conn *conn, *tmp; 1158 int rc; 1159 1160 if (spdk_unlikely(STAILQ_EMPTY(&group->connections))) { 1161 return 0; 1162 } 1163 1164 rc = spdk_sock_group_poll(group->sock_group); 1165 if (rc < 0) { 1166 SPDK_ERRLOG("Failed to poll sock_group=%p\n", group->sock_group); 1167 } 1168 1169 STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) { 1170 if (conn->state == ISCSI_CONN_STATE_EXITING) { 1171 spdk_iscsi_conn_destruct(conn); 1172 } 1173 } 1174 1175 return -1; 1176 } 1177 1178 static int 1179 spdk_iscsi_poll_group_handle_nop(void *ctx) 1180 { 1181 struct spdk_iscsi_poll_group *group = ctx; 1182 struct spdk_iscsi_conn *conn, *tmp; 1183 1184 STAILQ_FOREACH_SAFE(conn, &group->connections, link, tmp) { 1185 spdk_iscsi_conn_handle_nop(conn); 1186 } 1187 1188 return -1; 1189 } 1190 1191 static void 1192 iscsi_create_poll_group(void *ctx) 1193 { 1194 struct spdk_iscsi_poll_group *pg; 1195 1196 assert(g_spdk_iscsi.poll_group != NULL); 1197 pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()]; 1198 pg->core = spdk_env_get_current_core(); 1199 1200 STAILQ_INIT(&pg->connections); 1201 pg->sock_group = spdk_sock_group_create(); 1202 assert(pg->sock_group != NULL); 1203 1204 pg->poller = spdk_poller_register(spdk_iscsi_poll_group_poll, pg, 0); 1205 /* set the period to 1 sec */ 1206 pg->nop_poller = spdk_poller_register(spdk_iscsi_poll_group_handle_nop, pg, 1000000); 1207 } 1208 1209 static void 1210 iscsi_unregister_poll_group(void *ctx) 1211 { 1212 struct spdk_iscsi_poll_group *pg; 1213 1214 assert(g_spdk_iscsi.poll_group != NULL); 1215 pg = &g_spdk_iscsi.poll_group[spdk_env_get_current_core()]; 1216 assert(pg->poller != NULL); 1217 assert(pg->sock_group != NULL); 1218 1219 spdk_sock_group_close(&pg->sock_group); 1220 spdk_poller_unregister(&pg->poller); 1221 spdk_poller_unregister(&pg->nop_poller); 1222 } 1223 1224 static void 1225 spdk_initialize_iscsi_poll_group(spdk_msg_fn cpl) 1226 { 1227 size_t g_num_poll_groups = spdk_env_get_last_core() + 1; 1228 1229 g_spdk_iscsi.poll_group = calloc(g_num_poll_groups, sizeof(struct spdk_iscsi_poll_group)); 1230 if (!g_spdk_iscsi.poll_group) { 1231 SPDK_ERRLOG("Failed to allocated iscsi poll group\n"); 1232 spdk_iscsi_init_complete(-1); 1233 return; 1234 } 1235 1236 /* Send a message to each thread and create a poll group */ 1237 spdk_for_each_thread(iscsi_create_poll_group, NULL, cpl); 1238 } 1239 1240 static void 1241 spdk_iscsi_parse_configuration(void *ctx) 1242 { 1243 int rc; 1244 1245 rc = spdk_iscsi_parse_portal_grps(); 1246 if (rc < 0) { 1247 SPDK_ERRLOG("spdk_iscsi_parse_portal_grps() failed\n"); 1248 goto end; 1249 } 1250 1251 rc = spdk_iscsi_parse_init_grps(); 1252 if (rc < 0) { 1253 SPDK_ERRLOG("spdk_iscsi_parse_init_grps() failed\n"); 1254 goto end; 1255 } 1256 1257 rc = spdk_iscsi_parse_tgt_nodes(); 1258 if (rc < 0) { 1259 SPDK_ERRLOG("spdk_iscsi_parse_tgt_nodes() failed\n"); 1260 } 1261 1262 if (g_spdk_iscsi.authfile != NULL) { 1263 if (access(g_spdk_iscsi.authfile, R_OK) == 0) { 1264 rc = spdk_iscsi_parse_auth_info(); 1265 if (rc < 0) { 1266 SPDK_ERRLOG("spdk_iscsi_parse_auth_info() failed\n"); 1267 } 1268 } else { 1269 SPDK_INFOLOG(SPDK_LOG_ISCSI, "CHAP secret file is not found in the path %s\n", 1270 g_spdk_iscsi.authfile); 1271 } 1272 } 1273 1274 end: 1275 spdk_iscsi_init_complete(rc); 1276 } 1277 1278 static int 1279 spdk_iscsi_parse_globals(void) 1280 { 1281 int rc; 1282 1283 rc = spdk_iscsi_initialize_global_params(); 1284 if (rc != 0) { 1285 SPDK_ERRLOG("spdk_iscsi_initialize_iscsi_global_params() failed\n"); 1286 return rc; 1287 } 1288 1289 g_spdk_iscsi.session = spdk_dma_zmalloc(sizeof(void *) * g_spdk_iscsi.MaxSessions, 0, NULL); 1290 if (!g_spdk_iscsi.session) { 1291 SPDK_ERRLOG("spdk_dma_zmalloc() failed for session array\n"); 1292 return -1; 1293 } 1294 1295 /* 1296 * For now, just support same number of total connections, rather 1297 * than MaxSessions * MaxConnectionsPerSession. After we add better 1298 * handling for low resource conditions from our various buffer 1299 * pools, we can bump this up to support more connections. 1300 */ 1301 g_spdk_iscsi.MaxConnections = g_spdk_iscsi.MaxSessions; 1302 1303 rc = spdk_iscsi_initialize_all_pools(); 1304 if (rc != 0) { 1305 SPDK_ERRLOG("spdk_initialize_all_pools() failed\n"); 1306 return -1; 1307 } 1308 1309 rc = spdk_initialize_iscsi_conns(); 1310 if (rc < 0) { 1311 SPDK_ERRLOG("spdk_initialize_iscsi_conns() failed\n"); 1312 return rc; 1313 } 1314 1315 spdk_initialize_iscsi_poll_group(spdk_iscsi_parse_configuration); 1316 return 0; 1317 } 1318 1319 void 1320 spdk_iscsi_init(spdk_iscsi_init_cb cb_fn, void *cb_arg) 1321 { 1322 int rc; 1323 1324 assert(cb_fn != NULL); 1325 g_init_cb_fn = cb_fn; 1326 g_init_cb_arg = cb_arg; 1327 1328 rc = spdk_iscsi_parse_globals(); 1329 if (rc < 0) { 1330 SPDK_ERRLOG("spdk_iscsi_parse_globals() failed\n"); 1331 spdk_iscsi_init_complete(-1); 1332 } 1333 1334 /* 1335 * spdk_iscsi_parse_configuration() will be called as the callback to 1336 * spdk_initialize_iscsi_poll_group() and will complete iSCSI 1337 * subsystem initialization. 1338 */ 1339 } 1340 1341 void 1342 spdk_iscsi_fini(spdk_iscsi_fini_cb cb_fn, void *cb_arg) 1343 { 1344 g_fini_cb_fn = cb_fn; 1345 g_fini_cb_arg = cb_arg; 1346 1347 spdk_iscsi_portal_grp_close_all(); 1348 spdk_shutdown_iscsi_conns(); 1349 } 1350 1351 static void 1352 spdk_iscsi_fini_done(void *arg) 1353 { 1354 spdk_iscsi_check_pools(); 1355 spdk_iscsi_free_pools(); 1356 1357 spdk_iscsi_shutdown_tgt_nodes(); 1358 spdk_iscsi_init_grps_destroy(); 1359 spdk_iscsi_portal_grps_destroy(); 1360 spdk_iscsi_auth_groups_destroy(); 1361 free(g_spdk_iscsi.authfile); 1362 free(g_spdk_iscsi.nodebase); 1363 free(g_spdk_iscsi.poll_group); 1364 1365 pthread_mutex_destroy(&g_spdk_iscsi.mutex); 1366 g_fini_cb_fn(g_fini_cb_arg); 1367 } 1368 1369 void 1370 spdk_shutdown_iscsi_conns_done(void) 1371 { 1372 if (g_spdk_iscsi.poll_group) { 1373 spdk_for_each_thread(iscsi_unregister_poll_group, NULL, spdk_iscsi_fini_done); 1374 } else { 1375 spdk_iscsi_fini_done(NULL); 1376 } 1377 } 1378 1379 void 1380 spdk_iscsi_config_text(FILE *fp) 1381 { 1382 spdk_iscsi_globals_config_text(fp); 1383 spdk_iscsi_portal_grps_config_text(fp); 1384 spdk_iscsi_init_grps_config_text(fp); 1385 spdk_iscsi_tgt_nodes_config_text(fp); 1386 } 1387 1388 void 1389 spdk_iscsi_opts_info_json(struct spdk_json_write_ctx *w) 1390 { 1391 spdk_json_write_object_begin(w); 1392 1393 if (g_spdk_iscsi.authfile != NULL) { 1394 spdk_json_write_named_string(w, "auth_file", g_spdk_iscsi.authfile); 1395 } 1396 spdk_json_write_named_string(w, "node_base", g_spdk_iscsi.nodebase); 1397 1398 spdk_json_write_named_uint32(w, "max_sessions", g_spdk_iscsi.MaxSessions); 1399 spdk_json_write_named_uint32(w, "max_connections_per_session", 1400 g_spdk_iscsi.MaxConnectionsPerSession); 1401 1402 spdk_json_write_named_uint32(w, "max_queue_depth", g_spdk_iscsi.MaxQueueDepth); 1403 1404 spdk_json_write_named_uint32(w, "default_time2wait", g_spdk_iscsi.DefaultTime2Wait); 1405 spdk_json_write_named_uint32(w, "default_time2retain", g_spdk_iscsi.DefaultTime2Retain); 1406 1407 spdk_json_write_named_uint32(w, "first_burst_length", g_spdk_iscsi.FirstBurstLength); 1408 1409 spdk_json_write_named_bool(w, "immediate_data", g_spdk_iscsi.ImmediateData); 1410 1411 spdk_json_write_named_bool(w, "allow_duplicated_isid", g_spdk_iscsi.AllowDuplicateIsid); 1412 1413 spdk_json_write_named_uint32(w, "error_recovery_level", g_spdk_iscsi.ErrorRecoveryLevel); 1414 1415 spdk_json_write_named_int32(w, "nop_timeout", g_spdk_iscsi.timeout); 1416 spdk_json_write_named_int32(w, "nop_in_interval", g_spdk_iscsi.nopininterval); 1417 1418 spdk_json_write_named_bool(w, "disable_chap", g_spdk_iscsi.disable_chap); 1419 spdk_json_write_named_bool(w, "require_chap", g_spdk_iscsi.require_chap); 1420 spdk_json_write_named_bool(w, "mutual_chap", g_spdk_iscsi.mutual_chap); 1421 spdk_json_write_named_int32(w, "chap_group", g_spdk_iscsi.chap_group); 1422 1423 spdk_json_write_named_uint32(w, "min_connections_per_core", 1424 spdk_iscsi_conn_get_min_per_core()); 1425 1426 spdk_json_write_object_end(w); 1427 } 1428 1429 static void 1430 spdk_iscsi_auth_group_info_json(struct spdk_iscsi_auth_group *group, 1431 struct spdk_json_write_ctx *w) 1432 { 1433 struct spdk_iscsi_auth_secret *_secret; 1434 1435 spdk_json_write_object_begin(w); 1436 1437 spdk_json_write_named_int32(w, "tag", group->tag); 1438 1439 spdk_json_write_named_array_begin(w, "secrets"); 1440 TAILQ_FOREACH(_secret, &group->secret_head, tailq) { 1441 spdk_json_write_object_begin(w); 1442 1443 spdk_json_write_named_string(w, "user", _secret->user); 1444 spdk_json_write_named_string(w, "secret", _secret->secret); 1445 1446 if (_secret->muser[0] != '\0') { 1447 spdk_json_write_named_string(w, "muser", _secret->muser); 1448 spdk_json_write_named_string(w, "msecret", _secret->msecret); 1449 } 1450 1451 spdk_json_write_object_end(w); 1452 } 1453 spdk_json_write_array_end(w); 1454 1455 spdk_json_write_object_end(w); 1456 } 1457 1458 static void 1459 spdk_iscsi_auth_group_config_json(struct spdk_iscsi_auth_group *group, 1460 struct spdk_json_write_ctx *w) 1461 { 1462 spdk_json_write_object_begin(w); 1463 1464 spdk_json_write_named_string(w, "method", "add_iscsi_auth_group"); 1465 1466 spdk_json_write_name(w, "params"); 1467 spdk_iscsi_auth_group_info_json(group, w); 1468 1469 spdk_json_write_object_end(w); 1470 } 1471 1472 void 1473 spdk_iscsi_auth_groups_info_json(struct spdk_json_write_ctx *w) 1474 { 1475 struct spdk_iscsi_auth_group *group; 1476 1477 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 1478 spdk_iscsi_auth_group_info_json(group, w); 1479 } 1480 } 1481 1482 static void 1483 spdk_iscsi_auth_groups_config_json(struct spdk_json_write_ctx *w) 1484 { 1485 struct spdk_iscsi_auth_group *group; 1486 1487 TAILQ_FOREACH(group, &g_spdk_iscsi.auth_group_head, tailq) { 1488 spdk_iscsi_auth_group_config_json(group, w); 1489 } 1490 } 1491 1492 static void 1493 spdk_iscsi_opts_config_json(struct spdk_json_write_ctx *w) 1494 { 1495 spdk_json_write_object_begin(w); 1496 1497 spdk_json_write_named_string(w, "method", "set_iscsi_options"); 1498 1499 spdk_json_write_name(w, "params"); 1500 spdk_iscsi_opts_info_json(w); 1501 1502 spdk_json_write_object_end(w); 1503 } 1504 1505 void 1506 spdk_iscsi_config_json(struct spdk_json_write_ctx *w) 1507 { 1508 spdk_json_write_array_begin(w); 1509 spdk_iscsi_opts_config_json(w); 1510 spdk_iscsi_portal_grps_config_json(w); 1511 spdk_iscsi_init_grps_config_json(w); 1512 spdk_iscsi_tgt_nodes_config_json(w); 1513 spdk_iscsi_auth_groups_config_json(w); 1514 spdk_json_write_array_end(w); 1515 } 1516 1517 SPDK_LOG_REGISTER_COMPONENT("iscsi", SPDK_LOG_ISCSI) 1518