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 "iscsi/iscsi.h" 36 #include "iscsi/conn.h" 37 #include "iscsi/tgt_node.h" 38 #include "iscsi/portal_grp.h" 39 #include "iscsi/init_grp.h" 40 41 #include "spdk/rpc.h" 42 #include "spdk/util.h" 43 44 #include "spdk_internal/log.h" 45 46 static void 47 spdk_rpc_get_initiator_groups(struct spdk_jsonrpc_request *request, 48 const struct spdk_json_val *params) 49 { 50 struct spdk_json_write_ctx *w; 51 struct spdk_iscsi_init_grp *ig; 52 int i; 53 54 if (params != NULL) { 55 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 56 "get_initiator_groups requires no parameters"); 57 return; 58 } 59 60 w = spdk_jsonrpc_begin_result(request); 61 if (w == NULL) { 62 return; 63 } 64 65 spdk_json_write_array_begin(w); 66 67 TAILQ_FOREACH(ig, &g_spdk_iscsi.ig_head, tailq) { 68 spdk_json_write_object_begin(w); 69 70 spdk_json_write_name(w, "initiators"); 71 spdk_json_write_array_begin(w); 72 for (i = 0; i < ig->ninitiators; i++) { 73 spdk_json_write_string(w, ig->initiators[i]); 74 } 75 spdk_json_write_array_end(w); 76 77 spdk_json_write_name(w, "tag"); 78 spdk_json_write_int32(w, ig->tag); 79 80 spdk_json_write_name(w, "netmasks"); 81 spdk_json_write_array_begin(w); 82 for (i = 0; i < ig->nnetmasks; i++) { 83 spdk_json_write_string(w, ig->netmasks[i]); 84 } 85 spdk_json_write_array_end(w); 86 87 spdk_json_write_object_end(w); 88 } 89 90 spdk_json_write_array_end(w); 91 92 spdk_jsonrpc_end_result(request, w); 93 } 94 SPDK_RPC_REGISTER("get_initiator_groups", spdk_rpc_get_initiator_groups) 95 96 struct rpc_initiator_list { 97 size_t num_initiators; 98 char *initiators[MAX_INITIATOR]; 99 }; 100 101 static int 102 decode_rpc_initiator_list(const struct spdk_json_val *val, void *out) 103 { 104 struct rpc_initiator_list *list = out; 105 106 return spdk_json_decode_array(val, spdk_json_decode_string, list->initiators, MAX_INITIATOR, 107 &list->num_initiators, sizeof(char *)); 108 } 109 110 static void 111 free_rpc_initiator_list(struct rpc_initiator_list *list) 112 { 113 size_t i; 114 115 for (i = 0; i < list->num_initiators; i++) { 116 free(list->initiators[i]); 117 } 118 } 119 120 struct rpc_netmask_list { 121 size_t num_netmasks; 122 char *netmasks[MAX_NETMASK]; 123 }; 124 125 static int 126 decode_rpc_netmask_list(const struct spdk_json_val *val, void *out) 127 { 128 struct rpc_netmask_list *list = out; 129 130 return spdk_json_decode_array(val, spdk_json_decode_string, list->netmasks, MAX_NETMASK, 131 &list->num_netmasks, sizeof(char *)); 132 } 133 134 static void 135 free_rpc_netmask_list(struct rpc_netmask_list *list) 136 { 137 size_t i; 138 139 for (i = 0; i < list->num_netmasks; i++) { 140 free(list->netmasks[i]); 141 } 142 } 143 144 struct rpc_initiator_group { 145 int32_t tag; 146 struct rpc_initiator_list initiator_list; 147 struct rpc_netmask_list netmask_list; 148 }; 149 150 static void 151 free_rpc_initiator_group(struct rpc_initiator_group *ig) 152 { 153 free_rpc_initiator_list(&ig->initiator_list); 154 free_rpc_netmask_list(&ig->netmask_list); 155 } 156 157 static const struct spdk_json_object_decoder rpc_initiator_group_decoders[] = { 158 {"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32}, 159 {"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list}, 160 {"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list}, 161 }; 162 163 static void 164 spdk_rpc_add_initiator_group(struct spdk_jsonrpc_request *request, 165 const struct spdk_json_val *params) 166 { 167 struct rpc_initiator_group req = {}; 168 size_t i; 169 char **initiators = NULL, **netmasks = NULL; 170 struct spdk_json_write_ctx *w; 171 172 if (spdk_json_decode_object(params, rpc_initiator_group_decoders, 173 SPDK_COUNTOF(rpc_initiator_group_decoders), &req)) { 174 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 175 goto invalid; 176 } 177 178 if (req.initiator_list.num_initiators == 0 || 179 req.netmask_list.num_netmasks == 0) { 180 goto invalid; 181 } 182 183 initiators = calloc(req.initiator_list.num_initiators, sizeof(char *)); 184 if (initiators == NULL) { 185 goto invalid; 186 } 187 for (i = 0; i < req.initiator_list.num_initiators; i++) { 188 initiators[i] = strdup(req.initiator_list.initiators[i]); 189 if (initiators[i] == NULL) { 190 goto invalid; 191 } 192 } 193 194 netmasks = calloc(req.netmask_list.num_netmasks, sizeof(char *)); 195 if (netmasks == NULL) { 196 goto invalid; 197 } 198 for (i = 0; i < req.netmask_list.num_netmasks; i++) { 199 netmasks[i] = strdup(req.netmask_list.netmasks[i]); 200 if (netmasks[i] == NULL) { 201 goto invalid; 202 } 203 } 204 205 if (spdk_iscsi_init_grp_create_from_initiator_list(req.tag, 206 req.initiator_list.num_initiators, 207 initiators, 208 req.netmask_list.num_netmasks, 209 netmasks)) { 210 SPDK_ERRLOG("create_from_initiator_list failed\n"); 211 goto invalid; 212 } 213 214 free_rpc_initiator_group(&req); 215 216 w = spdk_jsonrpc_begin_result(request); 217 if (w == NULL) { 218 return; 219 } 220 221 spdk_json_write_bool(w, true); 222 spdk_jsonrpc_end_result(request, w); 223 return; 224 225 invalid: 226 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 227 if (initiators) { 228 for (i = 0; i < req.initiator_list.num_initiators; i++) { 229 free(initiators[i]); 230 } 231 free(initiators); 232 } 233 if (netmasks) { 234 for (i = 0; i < req.netmask_list.num_netmasks; i++) { 235 free(netmasks[i]); 236 } 237 free(netmasks); 238 } 239 free_rpc_initiator_group(&req); 240 } 241 SPDK_RPC_REGISTER("add_initiator_group", spdk_rpc_add_initiator_group) 242 243 struct rpc_delete_initiator_group { 244 int32_t tag; 245 }; 246 247 static const struct spdk_json_object_decoder rpc_delete_initiator_group_decoders[] = { 248 {"tag", offsetof(struct rpc_delete_initiator_group, tag), spdk_json_decode_int32}, 249 }; 250 251 static void 252 spdk_rpc_delete_initiator_group(struct spdk_jsonrpc_request *request, 253 const struct spdk_json_val *params) 254 { 255 struct rpc_delete_initiator_group req = {}; 256 struct spdk_json_write_ctx *w; 257 struct spdk_iscsi_init_grp *ig; 258 259 if (spdk_json_decode_object(params, rpc_delete_initiator_group_decoders, 260 SPDK_COUNTOF(rpc_delete_initiator_group_decoders), 261 &req)) { 262 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 263 goto invalid; 264 } 265 266 if (spdk_iscsi_init_grp_deletable(req.tag)) { 267 goto invalid; 268 } 269 270 ig = spdk_iscsi_init_grp_find_by_tag(req.tag); 271 if (!ig) { 272 goto invalid; 273 } 274 spdk_iscsi_tgt_node_delete_map(NULL, ig); 275 spdk_iscsi_init_grp_release(ig); 276 277 w = spdk_jsonrpc_begin_result(request); 278 if (w == NULL) { 279 return; 280 } 281 282 spdk_json_write_bool(w, true); 283 spdk_jsonrpc_end_result(request, w); 284 return; 285 286 invalid: 287 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 288 } 289 SPDK_RPC_REGISTER("delete_initiator_group", spdk_rpc_delete_initiator_group) 290 291 static void 292 spdk_rpc_get_target_nodes(struct spdk_jsonrpc_request *request, 293 const struct spdk_json_val *params) 294 { 295 struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi; 296 struct spdk_json_write_ctx *w; 297 size_t tgt_idx; 298 int i; 299 300 if (params != NULL) { 301 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 302 "get_target_nodes requires no parameters"); 303 return; 304 } 305 306 w = spdk_jsonrpc_begin_result(request); 307 if (w == NULL) { 308 return; 309 } 310 311 spdk_json_write_array_begin(w); 312 313 for (tgt_idx = 0 ; tgt_idx < MAX_ISCSI_TARGET_NODE; tgt_idx++) { 314 struct spdk_iscsi_tgt_node *tgtnode = iscsi->target[tgt_idx]; 315 316 if (tgtnode == NULL) { 317 continue; 318 } 319 320 spdk_json_write_object_begin(w); 321 322 spdk_json_write_name(w, "name"); 323 spdk_json_write_string(w, tgtnode->name); 324 325 if (tgtnode->alias) { 326 spdk_json_write_name(w, "alias_name"); 327 spdk_json_write_string(w, tgtnode->alias); 328 } 329 330 spdk_json_write_name(w, "pg_ig_maps"); 331 spdk_json_write_array_begin(w); 332 for (i = 0; i < tgtnode->maxmap; i++) { 333 spdk_json_write_object_begin(w); 334 spdk_json_write_name(w, "pg_tag"); 335 spdk_json_write_int32(w, tgtnode->map[i].pg->tag); 336 spdk_json_write_name(w, "ig_tag"); 337 spdk_json_write_int32(w, tgtnode->map[i].ig->tag); 338 spdk_json_write_object_end(w); 339 } 340 spdk_json_write_array_end(w); 341 342 spdk_json_write_name(w, "luns"); 343 spdk_json_write_array_begin(w); 344 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 345 struct spdk_scsi_lun *lun = spdk_scsi_dev_get_lun(tgtnode->dev, i); 346 347 if (lun) { 348 spdk_json_write_object_begin(w); 349 spdk_json_write_name(w, "name"); 350 spdk_json_write_string(w, spdk_scsi_lun_get_name(lun)); 351 spdk_json_write_name(w, "id"); 352 spdk_json_write_int32(w, spdk_scsi_lun_get_id(lun)); 353 spdk_json_write_object_end(w); 354 } 355 } 356 spdk_json_write_array_end(w); 357 358 spdk_json_write_name(w, "queue_depth"); 359 spdk_json_write_int32(w, tgtnode->queue_depth); 360 361 /* 362 * TODO: convert these to bool 363 */ 364 365 spdk_json_write_name(w, "chap_disabled"); 366 spdk_json_write_int32(w, tgtnode->auth_chap_disabled); 367 368 spdk_json_write_name(w, "chap_required"); 369 spdk_json_write_int32(w, tgtnode->auth_chap_required); 370 371 spdk_json_write_name(w, "chap_mutual"); 372 spdk_json_write_int32(w, tgtnode->auth_chap_mutual); 373 374 spdk_json_write_name(w, "chap_auth_group"); 375 spdk_json_write_int32(w, tgtnode->auth_group); 376 377 spdk_json_write_object_end(w); 378 } 379 spdk_json_write_array_end(w); 380 381 spdk_jsonrpc_end_result(request, w); 382 } 383 SPDK_RPC_REGISTER("get_target_nodes", spdk_rpc_get_target_nodes) 384 385 struct rpc_pg_tags { 386 size_t num_tags; 387 int32_t tags[MAX_TARGET_MAP]; 388 }; 389 390 static int 391 decode_rpc_pg_tags(const struct spdk_json_val *val, void *out) 392 { 393 struct rpc_pg_tags *pg_tags = out; 394 395 return spdk_json_decode_array(val, spdk_json_decode_int32, pg_tags->tags, MAX_TARGET_MAP, 396 &pg_tags->num_tags, sizeof(int32_t)); 397 } 398 399 struct rpc_ig_tags { 400 size_t num_tags; 401 int32_t tags[MAX_TARGET_MAP]; 402 }; 403 404 static int 405 decode_rpc_ig_tags(const struct spdk_json_val *val, void *out) 406 { 407 struct rpc_ig_tags *ig_tags = out; 408 409 return spdk_json_decode_array(val, spdk_json_decode_int32, ig_tags->tags, MAX_TARGET_MAP, 410 &ig_tags->num_tags, sizeof(int32_t)); 411 } 412 413 #define RPC_CONSTRUCT_TARGET_NODE_MAX_LUN 64 414 415 struct rpc_lun_names { 416 size_t num_names; 417 char *names[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN]; 418 }; 419 420 static int 421 decode_rpc_lun_names(const struct spdk_json_val *val, void *out) 422 { 423 struct rpc_lun_names *lun_names = out; 424 425 return spdk_json_decode_array(val, spdk_json_decode_string, lun_names->names, 426 RPC_CONSTRUCT_TARGET_NODE_MAX_LUN, 427 &lun_names->num_names, sizeof(char *)); 428 } 429 430 static void 431 free_rpc_lun_names(struct rpc_lun_names *r) 432 { 433 size_t i; 434 435 for (i = 0; i < r->num_names; i++) { 436 free(r->names[i]); 437 } 438 } 439 440 struct rpc_lun_ids { 441 size_t num_ids; 442 int32_t ids[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN]; 443 }; 444 445 static int 446 decode_rpc_lun_ids(const struct spdk_json_val *val, void *out) 447 { 448 struct rpc_lun_ids *lun_ids = out; 449 450 return spdk_json_decode_array(val, spdk_json_decode_int32, lun_ids->ids, 451 RPC_CONSTRUCT_TARGET_NODE_MAX_LUN, 452 &lun_ids->num_ids, sizeof(int32_t)); 453 } 454 455 struct rpc_target_node { 456 char *name; 457 char *alias_name; 458 459 struct rpc_pg_tags pg_tags; 460 struct rpc_ig_tags ig_tags; 461 462 struct rpc_lun_names lun_names; 463 struct rpc_lun_ids lun_ids; 464 465 int32_t queue_depth; 466 int32_t chap_disabled; 467 int32_t chap_required; 468 int32_t chap_mutual; 469 int32_t chap_auth_group; 470 }; 471 472 static void 473 free_rpc_target_node(struct rpc_target_node *req) 474 { 475 free(req->name); 476 free(req->alias_name); 477 free_rpc_lun_names(&req->lun_names); 478 } 479 480 static const struct spdk_json_object_decoder rpc_target_node_decoders[] = { 481 {"name", offsetof(struct rpc_target_node, name), spdk_json_decode_string}, 482 {"alias_name", offsetof(struct rpc_target_node, alias_name), spdk_json_decode_string}, 483 {"pg_tags", offsetof(struct rpc_target_node, pg_tags), decode_rpc_pg_tags}, 484 {"ig_tags", offsetof(struct rpc_target_node, ig_tags), decode_rpc_ig_tags}, 485 {"lun_names", offsetof(struct rpc_target_node, lun_names), decode_rpc_lun_names}, 486 {"lun_ids", offsetof(struct rpc_target_node, lun_ids), decode_rpc_lun_ids}, 487 {"queue_depth", offsetof(struct rpc_target_node, queue_depth), spdk_json_decode_int32}, 488 {"chap_disabled", offsetof(struct rpc_target_node, chap_disabled), spdk_json_decode_int32}, 489 {"chap_required", offsetof(struct rpc_target_node, chap_required), spdk_json_decode_int32}, 490 {"chap_mutual", offsetof(struct rpc_target_node, chap_mutual), spdk_json_decode_int32}, 491 {"chap_auth_group", offsetof(struct rpc_target_node, chap_auth_group), spdk_json_decode_int32}, 492 }; 493 494 static void 495 spdk_rpc_construct_target_node(struct spdk_jsonrpc_request *request, 496 const struct spdk_json_val *params) 497 { 498 struct rpc_target_node req = {}; 499 struct spdk_json_write_ctx *w; 500 struct spdk_iscsi_tgt_node *target; 501 502 if (spdk_json_decode_object(params, rpc_target_node_decoders, 503 SPDK_COUNTOF(rpc_target_node_decoders), 504 &req)) { 505 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 506 goto invalid; 507 } 508 509 if (req.pg_tags.num_tags != req.ig_tags.num_tags) { 510 SPDK_ERRLOG("pg_tags/ig_tags count mismatch\n"); 511 goto invalid; 512 } 513 514 if (req.lun_names.num_names != req.lun_ids.num_ids) { 515 SPDK_ERRLOG("lun_names/lun_ids count mismatch\n"); 516 goto invalid; 517 } 518 519 /* 520 * Use default parameters in a few places: 521 * index = -1 : automatically pick an index for the new target node 522 * alias = NULL 523 * 0, 0 = disable header/data digests 524 */ 525 target = spdk_iscsi_tgt_node_construct(-1, req.name, req.alias_name, 526 req.pg_tags.tags, 527 req.ig_tags.tags, 528 req.pg_tags.num_tags, 529 req.lun_names.names, 530 req.lun_ids.ids, 531 req.lun_names.num_names, 532 req.queue_depth, 533 req.chap_disabled, 534 req.chap_required, 535 req.chap_mutual, 536 req.chap_auth_group, 537 0, 0); 538 539 if (target == NULL) { 540 goto invalid; 541 } 542 543 free_rpc_target_node(&req); 544 545 w = spdk_jsonrpc_begin_result(request); 546 if (w == NULL) { 547 return; 548 } 549 550 spdk_json_write_bool(w, true); 551 spdk_jsonrpc_end_result(request, w); 552 return; 553 554 invalid: 555 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 556 free_rpc_target_node(&req); 557 } 558 SPDK_RPC_REGISTER("construct_target_node", spdk_rpc_construct_target_node) 559 560 struct rpc_delete_target_node { 561 char *name; 562 }; 563 564 static void 565 free_rpc_delete_target_node(struct rpc_delete_target_node *r) 566 { 567 free(r->name); 568 } 569 570 static const struct spdk_json_object_decoder rpc_delete_target_node_decoders[] = { 571 {"name", offsetof(struct rpc_delete_target_node, name), spdk_json_decode_string}, 572 }; 573 574 static void 575 spdk_rpc_delete_target_node(struct spdk_jsonrpc_request *request, 576 const struct spdk_json_val *params) 577 { 578 struct rpc_delete_target_node req = {}; 579 struct spdk_json_write_ctx *w; 580 581 if (spdk_json_decode_object(params, rpc_delete_target_node_decoders, 582 SPDK_COUNTOF(rpc_delete_target_node_decoders), 583 &req)) { 584 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 585 goto invalid; 586 } 587 588 if (req.name == NULL) { 589 SPDK_ERRLOG("missing name param\n"); 590 goto invalid; 591 } 592 593 if (spdk_iscsi_shutdown_tgt_node_by_name(req.name)) { 594 SPDK_ERRLOG("shutdown_tgt_node_by_name failed\n"); 595 goto invalid; 596 } 597 598 free_rpc_delete_target_node(&req); 599 600 w = spdk_jsonrpc_begin_result(request); 601 if (w == NULL) { 602 return; 603 } 604 605 spdk_json_write_bool(w, true); 606 spdk_jsonrpc_end_result(request, w); 607 return; 608 609 invalid: 610 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 611 free_rpc_delete_target_node(&req); 612 } 613 SPDK_RPC_REGISTER("delete_target_node", spdk_rpc_delete_target_node) 614 615 static void 616 spdk_rpc_get_portal_groups(struct spdk_jsonrpc_request *request, 617 const struct spdk_json_val *params) 618 { 619 struct spdk_json_write_ctx *w; 620 struct spdk_iscsi_portal_grp *pg; 621 struct spdk_iscsi_portal *portal; 622 623 if (params != NULL) { 624 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 625 "get_portal_groups requires no parameters"); 626 return; 627 } 628 629 w = spdk_jsonrpc_begin_result(request); 630 if (w == NULL) { 631 return; 632 } 633 634 spdk_json_write_array_begin(w); 635 636 TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) { 637 spdk_json_write_object_begin(w); 638 639 spdk_json_write_name(w, "portals"); 640 spdk_json_write_array_begin(w); 641 TAILQ_FOREACH(portal, &pg->head, tailq) { 642 spdk_json_write_object_begin(w); 643 spdk_json_write_name(w, "host"); 644 spdk_json_write_string(w, portal->host); 645 spdk_json_write_name(w, "port"); 646 spdk_json_write_string(w, portal->port); 647 spdk_json_write_object_end(w); 648 } 649 spdk_json_write_array_end(w); 650 651 spdk_json_write_name(w, "tag"); 652 spdk_json_write_int32(w, pg->tag); 653 654 spdk_json_write_object_end(w); 655 } 656 657 spdk_json_write_array_end(w); 658 659 spdk_jsonrpc_end_result(request, w); 660 } 661 SPDK_RPC_REGISTER("get_portal_groups", spdk_rpc_get_portal_groups) 662 663 struct rpc_portal { 664 char *host; 665 char *port; 666 }; 667 668 struct rpc_portal_list { 669 size_t num_portals; 670 struct rpc_portal portals[MAX_PORTAL]; 671 }; 672 673 struct rpc_portal_group { 674 int32_t tag; 675 struct rpc_portal_list portal_list; 676 }; 677 678 static void 679 free_rpc_portal(struct rpc_portal *portal) 680 { 681 free(portal->host); 682 portal->host = NULL; 683 free(portal->port); 684 portal->port = NULL; 685 } 686 687 static void 688 free_rpc_portal_list(struct rpc_portal_list *pl) 689 { 690 size_t i; 691 692 for (i = 0; i < pl->num_portals; i++) { 693 free_rpc_portal(&pl->portals[i]); 694 } 695 pl->num_portals = 0; 696 } 697 698 static void 699 free_rpc_portal_group(struct rpc_portal_group *pg) 700 { 701 free_rpc_portal_list(&pg->portal_list); 702 } 703 704 static const struct spdk_json_object_decoder rpc_portal_decoders[] = { 705 {"host", offsetof(struct rpc_portal, host), spdk_json_decode_string}, 706 {"port", offsetof(struct rpc_portal, port), spdk_json_decode_string}, 707 }; 708 709 static int 710 decode_rpc_portal(const struct spdk_json_val *val, void *out) 711 { 712 struct rpc_portal *portal = out; 713 714 return spdk_json_decode_object(val, rpc_portal_decoders, 715 SPDK_COUNTOF(rpc_portal_decoders), 716 portal); 717 } 718 719 static int 720 decode_rpc_portal_list(const struct spdk_json_val *val, void *out) 721 { 722 struct rpc_portal_list *list = out; 723 724 return spdk_json_decode_array(val, decode_rpc_portal, list->portals, MAX_PORTAL, &list->num_portals, 725 sizeof(struct rpc_portal)); 726 } 727 728 static const struct spdk_json_object_decoder rpc_portal_group_decoders[] = { 729 {"tag", offsetof(struct rpc_portal_group, tag), spdk_json_decode_int32}, 730 {"portals", offsetof(struct rpc_portal_group, portal_list), decode_rpc_portal_list}, 731 }; 732 733 static void 734 spdk_rpc_add_portal_group(struct spdk_jsonrpc_request *request, 735 const struct spdk_json_val *params) 736 { 737 struct rpc_portal_group req = {}; 738 struct spdk_iscsi_portal *portal_list[MAX_PORTAL] = {}; 739 struct spdk_json_write_ctx *w; 740 size_t i; 741 int rc = -1; 742 743 if (spdk_json_decode_object(params, rpc_portal_group_decoders, 744 SPDK_COUNTOF(rpc_portal_group_decoders), 745 &req)) { 746 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 747 goto out; 748 } 749 750 for (i = 0; i < req.portal_list.num_portals; i++) { 751 portal_list[i] = spdk_iscsi_portal_create(req.portal_list.portals[i].host, 752 req.portal_list.portals[i].port, 0); 753 if (portal_list[i] == NULL) { 754 SPDK_ERRLOG("portal_list allocation failed\n"); 755 goto out; 756 } 757 } 758 759 rc = spdk_iscsi_portal_grp_create_from_portal_list(req.tag, portal_list, 760 req.portal_list.num_portals); 761 762 if (rc < 0) { 763 SPDK_ERRLOG("create_from_portal_list failed\n"); 764 } 765 766 out: 767 if (rc == 0) { 768 w = spdk_jsonrpc_begin_result(request); 769 if (w != NULL) { 770 spdk_json_write_bool(w, true); 771 spdk_jsonrpc_end_result(request, w); 772 } 773 } else { 774 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 775 776 for (i = 0; i < req.portal_list.num_portals; i++) { 777 spdk_iscsi_portal_destroy(portal_list[i]); 778 } 779 } 780 free_rpc_portal_group(&req); 781 } 782 SPDK_RPC_REGISTER("add_portal_group", spdk_rpc_add_portal_group) 783 784 struct rpc_delete_portal_group { 785 int32_t tag; 786 }; 787 788 static const struct spdk_json_object_decoder rpc_delete_portal_group_decoders[] = { 789 {"tag", offsetof(struct rpc_delete_portal_group, tag), spdk_json_decode_int32}, 790 }; 791 792 static void 793 spdk_rpc_delete_portal_group(struct spdk_jsonrpc_request *request, 794 const struct spdk_json_val *params) 795 { 796 struct rpc_delete_portal_group req = {}; 797 struct spdk_json_write_ctx *w; 798 struct spdk_iscsi_portal_grp *pg; 799 800 if (spdk_json_decode_object(params, rpc_delete_portal_group_decoders, 801 SPDK_COUNTOF(rpc_delete_portal_group_decoders), 802 &req)) { 803 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 804 goto invalid; 805 } 806 807 if (spdk_iscsi_portal_grp_deletable(req.tag)) { 808 goto invalid; 809 } 810 811 pg = spdk_iscsi_portal_grp_find_by_tag(req.tag); 812 if (!pg) { 813 goto invalid; 814 } 815 816 spdk_iscsi_tgt_node_delete_map(pg, NULL); 817 spdk_iscsi_portal_grp_release(pg); 818 819 w = spdk_jsonrpc_begin_result(request); 820 if (w == NULL) { 821 return; 822 } 823 824 spdk_json_write_bool(w, true); 825 spdk_jsonrpc_end_result(request, w); 826 return; 827 828 invalid: 829 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 830 } 831 SPDK_RPC_REGISTER("delete_portal_group", spdk_rpc_delete_portal_group) 832 833 static void 834 spdk_rpc_get_iscsi_connections(struct spdk_jsonrpc_request *request, 835 const struct spdk_json_val *params) 836 { 837 struct spdk_json_write_ctx *w; 838 struct spdk_iscsi_conn *conns = g_conns_array; 839 int i; 840 uint16_t tsih; 841 842 if (params != NULL) { 843 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 844 "get_iscsi_connections requires no parameters"); 845 return; 846 } 847 848 w = spdk_jsonrpc_begin_result(request); 849 if (w == NULL) { 850 return; 851 } 852 853 spdk_json_write_array_begin(w); 854 855 for (i = 0; i < MAX_ISCSI_CONNECTIONS; i++) { 856 struct spdk_iscsi_conn *c = &conns[i]; 857 858 if (!c->is_valid) { 859 continue; 860 } 861 862 spdk_json_write_object_begin(w); 863 864 spdk_json_write_name(w, "id"); 865 spdk_json_write_int32(w, c->id); 866 867 spdk_json_write_name(w, "cid"); 868 spdk_json_write_int32(w, c->cid); 869 870 /* 871 * If we try to return data for a connection that has not 872 * logged in yet, the session will not be set. So in this 873 * case, return -1 for the tsih rather than segfaulting 874 * on the null c->sess. 875 */ 876 if (c->sess == NULL) { 877 tsih = -1; 878 } else { 879 tsih = c->sess->tsih; 880 } 881 spdk_json_write_name(w, "tsih"); 882 spdk_json_write_int32(w, tsih); 883 884 spdk_json_write_name(w, "is_idle"); 885 spdk_json_write_int32(w, c->is_idle); 886 887 spdk_json_write_name(w, "lcore_id"); 888 spdk_json_write_int32(w, c->lcore); 889 890 spdk_json_write_name(w, "initiator_addr"); 891 spdk_json_write_string(w, c->initiator_addr); 892 893 spdk_json_write_name(w, "target_addr"); 894 spdk_json_write_string(w, c->target_addr); 895 896 spdk_json_write_name(w, "target_node_name"); 897 spdk_json_write_string(w, c->target_short_name); 898 899 spdk_json_write_object_end(w); 900 } 901 spdk_json_write_array_end(w); 902 903 spdk_jsonrpc_end_result(request, w); 904 } 905 SPDK_RPC_REGISTER("get_iscsi_connections", spdk_rpc_get_iscsi_connections) 906