1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2016 Intel Corporation. All rights reserved. 3 * Copyright (c) 2018-2021 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 5 */ 6 7 #include "spdk/bdev.h" 8 #include "spdk/log.h" 9 #include "spdk/rpc.h" 10 #include "spdk/env.h" 11 #include "spdk/nvme.h" 12 #include "spdk/nvmf.h" 13 #include "spdk/string.h" 14 #include "spdk/util.h" 15 #include "spdk/bit_array.h" 16 17 #include "spdk_internal/assert.h" 18 19 #include "nvmf_internal.h" 20 21 static bool g_logged_deprecated_nvmf_get_subsystems = false; 22 23 static int rpc_ana_state_parse(const char *str, enum spdk_nvme_ana_state *ana_state); 24 25 static int 26 json_write_hex_str(struct spdk_json_write_ctx *w, const void *data, size_t size) 27 { 28 static const char hex_char[16] = "0123456789ABCDEF"; 29 const uint8_t *buf = data; 30 char *str, *out; 31 int rc; 32 33 str = malloc(size * 2 + 1); 34 if (str == NULL) { 35 return -1; 36 } 37 38 out = str; 39 while (size--) { 40 unsigned byte = *buf++; 41 42 out[0] = hex_char[(byte >> 4) & 0xF]; 43 out[1] = hex_char[byte & 0xF]; 44 45 out += 2; 46 } 47 *out = '\0'; 48 49 rc = spdk_json_write_string(w, str); 50 free(str); 51 52 return rc; 53 } 54 55 static int 56 hex_nybble_to_num(char c) 57 { 58 if (c >= '0' && c <= '9') { 59 return c - '0'; 60 } 61 62 if (c >= 'a' && c <= 'f') { 63 return c - 'a' + 0xA; 64 } 65 66 if (c >= 'A' && c <= 'F') { 67 return c - 'A' + 0xA; 68 } 69 70 return -1; 71 } 72 73 static int 74 hex_byte_to_num(const char *str) 75 { 76 int hi, lo; 77 78 hi = hex_nybble_to_num(str[0]); 79 if (hi < 0) { 80 return hi; 81 } 82 83 lo = hex_nybble_to_num(str[1]); 84 if (lo < 0) { 85 return lo; 86 } 87 88 return hi * 16 + lo; 89 } 90 91 static int 92 decode_hex_string_be(const char *str, uint8_t *out, size_t size) 93 { 94 size_t i; 95 96 /* Decode a string in "ABCDEF012345" format to its binary representation */ 97 for (i = 0; i < size; i++) { 98 int num = hex_byte_to_num(str); 99 100 if (num < 0) { 101 /* Invalid hex byte or end of string */ 102 return -1; 103 } 104 105 out[i] = (uint8_t)num; 106 str += 2; 107 } 108 109 if (i != size || *str != '\0') { 110 /* Length mismatch */ 111 return -1; 112 } 113 114 return 0; 115 } 116 117 static int 118 decode_ns_nguid(const struct spdk_json_val *val, void *out) 119 { 120 char *str = NULL; 121 int rc; 122 123 rc = spdk_json_decode_string(val, &str); 124 if (rc == 0) { 125 /* 16-byte NGUID */ 126 rc = decode_hex_string_be(str, out, 16); 127 } 128 129 free(str); 130 return rc; 131 } 132 133 static int 134 decode_ns_eui64(const struct spdk_json_val *val, void *out) 135 { 136 char *str = NULL; 137 int rc; 138 139 rc = spdk_json_decode_string(val, &str); 140 if (rc == 0) { 141 /* 8-byte EUI-64 */ 142 rc = decode_hex_string_be(str, out, 8); 143 } 144 145 free(str); 146 return rc; 147 } 148 149 struct rpc_get_subsystem { 150 char *nqn; 151 char *tgt_name; 152 }; 153 154 static const struct spdk_json_object_decoder rpc_get_subsystem_decoders[] = { 155 {"nqn", offsetof(struct rpc_get_subsystem, nqn), spdk_json_decode_string, true}, 156 {"tgt_name", offsetof(struct rpc_get_subsystem, tgt_name), spdk_json_decode_string, true}, 157 }; 158 159 static void 160 dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *subsystem) 161 { 162 struct spdk_nvmf_host *host; 163 struct spdk_nvmf_subsystem_listener *listener; 164 165 spdk_json_write_object_begin(w); 166 167 spdk_json_write_named_string(w, "nqn", spdk_nvmf_subsystem_get_nqn(subsystem)); 168 spdk_json_write_name(w, "subtype"); 169 if (spdk_nvmf_subsystem_get_type(subsystem) == SPDK_NVMF_SUBTYPE_NVME) { 170 spdk_json_write_string(w, "NVMe"); 171 } else { 172 spdk_json_write_string(w, "Discovery"); 173 } 174 175 spdk_json_write_named_array_begin(w, "listen_addresses"); 176 177 for (listener = spdk_nvmf_subsystem_get_first_listener(subsystem); listener != NULL; 178 listener = spdk_nvmf_subsystem_get_next_listener(subsystem, listener)) { 179 const struct spdk_nvme_transport_id *trid; 180 181 trid = spdk_nvmf_subsystem_listener_get_trid(listener); 182 183 spdk_json_write_object_begin(w); 184 185 /* NOTE: "transport" is kept for compatibility; new code should use "trtype". */ 186 /* TODO: Remove after SPDK v23.09 release. */ 187 spdk_json_write_named_string(w, "transport", trid->trstring); 188 nvmf_transport_listen_dump_trid(trid, w); 189 spdk_json_write_object_end(w); 190 } 191 spdk_json_write_array_end(w); 192 193 spdk_json_write_named_bool(w, "allow_any_host", 194 spdk_nvmf_subsystem_get_allow_any_host(subsystem)); 195 196 spdk_json_write_named_array_begin(w, "hosts"); 197 198 for (host = spdk_nvmf_subsystem_get_first_host(subsystem); host != NULL; 199 host = spdk_nvmf_subsystem_get_next_host(subsystem, host)) { 200 spdk_json_write_object_begin(w); 201 spdk_json_write_named_string(w, "nqn", spdk_nvmf_host_get_nqn(host)); 202 spdk_json_write_object_end(w); 203 } 204 spdk_json_write_array_end(w); 205 206 if (spdk_nvmf_subsystem_get_type(subsystem) == SPDK_NVMF_SUBTYPE_NVME) { 207 struct spdk_nvmf_ns *ns; 208 struct spdk_nvmf_ns_opts ns_opts; 209 uint32_t max_namespaces; 210 211 spdk_json_write_named_string(w, "serial_number", spdk_nvmf_subsystem_get_sn(subsystem)); 212 213 spdk_json_write_named_string(w, "model_number", spdk_nvmf_subsystem_get_mn(subsystem)); 214 215 max_namespaces = spdk_nvmf_subsystem_get_max_namespaces(subsystem); 216 if (max_namespaces != 0) { 217 spdk_json_write_named_uint32(w, "max_namespaces", max_namespaces); 218 } 219 220 spdk_json_write_named_uint32(w, "min_cntlid", spdk_nvmf_subsystem_get_min_cntlid(subsystem)); 221 spdk_json_write_named_uint32(w, "max_cntlid", spdk_nvmf_subsystem_get_max_cntlid(subsystem)); 222 223 spdk_json_write_named_array_begin(w, "namespaces"); 224 for (ns = spdk_nvmf_subsystem_get_first_ns(subsystem); ns != NULL; 225 ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns)) { 226 spdk_nvmf_ns_get_opts(ns, &ns_opts, sizeof(ns_opts)); 227 spdk_json_write_object_begin(w); 228 spdk_json_write_named_int32(w, "nsid", spdk_nvmf_ns_get_id(ns)); 229 spdk_json_write_named_string(w, "bdev_name", 230 spdk_bdev_get_name(spdk_nvmf_ns_get_bdev(ns))); 231 /* NOTE: "name" is kept for compatibility only - new code should use bdev_name. */ 232 spdk_json_write_named_string(w, "name", 233 spdk_bdev_get_name(spdk_nvmf_ns_get_bdev(ns))); 234 235 if (!spdk_mem_all_zero(ns_opts.nguid, sizeof(ns_opts.nguid))) { 236 spdk_json_write_name(w, "nguid"); 237 json_write_hex_str(w, ns_opts.nguid, sizeof(ns_opts.nguid)); 238 } 239 240 if (!spdk_mem_all_zero(ns_opts.eui64, sizeof(ns_opts.eui64))) { 241 spdk_json_write_name(w, "eui64"); 242 json_write_hex_str(w, ns_opts.eui64, sizeof(ns_opts.eui64)); 243 } 244 245 if (!spdk_uuid_is_null(&ns_opts.uuid)) { 246 spdk_json_write_named_uuid(w, "uuid", &ns_opts.uuid); 247 } 248 249 if (nvmf_subsystem_get_ana_reporting(subsystem)) { 250 spdk_json_write_named_uint32(w, "anagrpid", ns_opts.anagrpid); 251 } 252 253 spdk_json_write_object_end(w); 254 } 255 spdk_json_write_array_end(w); 256 } 257 spdk_json_write_object_end(w); 258 } 259 260 SPDK_LOG_DEPRECATION_REGISTER(rpc_nvmf_get_subsystems, 261 "listener.transport is deprecated in favor of trtype", 262 "v24.01", 0); 263 264 static void 265 rpc_nvmf_get_subsystems(struct spdk_jsonrpc_request *request, 266 const struct spdk_json_val *params) 267 { 268 struct rpc_get_subsystem req = { 0 }; 269 struct spdk_json_write_ctx *w; 270 struct spdk_nvmf_subsystem *subsystem = NULL; 271 struct spdk_nvmf_tgt *tgt; 272 273 /* Log only once */ 274 if (!g_logged_deprecated_nvmf_get_subsystems) { 275 SPDK_LOG_DEPRECATED(rpc_nvmf_get_subsystems); 276 g_logged_deprecated_nvmf_get_subsystems = true; 277 } 278 279 if (params) { 280 if (spdk_json_decode_object(params, rpc_get_subsystem_decoders, 281 SPDK_COUNTOF(rpc_get_subsystem_decoders), 282 &req)) { 283 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 284 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 285 return; 286 } 287 } 288 289 tgt = spdk_nvmf_get_tgt(req.tgt_name); 290 if (!tgt) { 291 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 292 "Unable to find a target."); 293 free(req.tgt_name); 294 free(req.nqn); 295 return; 296 } 297 298 if (req.nqn) { 299 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, req.nqn); 300 if (!subsystem) { 301 SPDK_ERRLOG("subsystem '%s' does not exist\n", req.nqn); 302 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 303 free(req.tgt_name); 304 free(req.nqn); 305 return; 306 } 307 } 308 309 w = spdk_jsonrpc_begin_result(request); 310 spdk_json_write_array_begin(w); 311 312 if (subsystem) { 313 dump_nvmf_subsystem(w, subsystem); 314 } else { 315 for (subsystem = spdk_nvmf_subsystem_get_first(tgt); subsystem != NULL; 316 subsystem = spdk_nvmf_subsystem_get_next(subsystem)) { 317 dump_nvmf_subsystem(w, subsystem); 318 } 319 } 320 321 spdk_json_write_array_end(w); 322 spdk_jsonrpc_end_result(request, w); 323 free(req.tgt_name); 324 free(req.nqn); 325 } 326 SPDK_RPC_REGISTER("nvmf_get_subsystems", rpc_nvmf_get_subsystems, SPDK_RPC_RUNTIME) 327 328 struct rpc_subsystem_create { 329 char *nqn; 330 char *serial_number; 331 char *model_number; 332 char *tgt_name; 333 uint32_t max_namespaces; 334 bool allow_any_host; 335 bool ana_reporting; 336 uint16_t min_cntlid; 337 uint16_t max_cntlid; 338 }; 339 340 static const struct spdk_json_object_decoder rpc_subsystem_create_decoders[] = { 341 {"nqn", offsetof(struct rpc_subsystem_create, nqn), spdk_json_decode_string}, 342 {"serial_number", offsetof(struct rpc_subsystem_create, serial_number), spdk_json_decode_string, true}, 343 {"model_number", offsetof(struct rpc_subsystem_create, model_number), spdk_json_decode_string, true}, 344 {"tgt_name", offsetof(struct rpc_subsystem_create, tgt_name), spdk_json_decode_string, true}, 345 {"max_namespaces", offsetof(struct rpc_subsystem_create, max_namespaces), spdk_json_decode_uint32, true}, 346 {"allow_any_host", offsetof(struct rpc_subsystem_create, allow_any_host), spdk_json_decode_bool, true}, 347 {"ana_reporting", offsetof(struct rpc_subsystem_create, ana_reporting), spdk_json_decode_bool, true}, 348 {"min_cntlid", offsetof(struct rpc_subsystem_create, min_cntlid), spdk_json_decode_uint16, true}, 349 {"max_cntlid", offsetof(struct rpc_subsystem_create, max_cntlid), spdk_json_decode_uint16, true}, 350 }; 351 352 static void 353 rpc_nvmf_subsystem_started(struct spdk_nvmf_subsystem *subsystem, 354 void *cb_arg, int status) 355 { 356 struct spdk_jsonrpc_request *request = cb_arg; 357 358 if (!status) { 359 spdk_jsonrpc_send_bool_response(request, true); 360 } else { 361 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 362 "Subsystem %s start failed", 363 subsystem->subnqn); 364 spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL); 365 } 366 } 367 368 static void 369 rpc_nvmf_create_subsystem(struct spdk_jsonrpc_request *request, 370 const struct spdk_json_val *params) 371 { 372 struct rpc_subsystem_create *req; 373 struct spdk_nvmf_subsystem *subsystem = NULL; 374 struct spdk_nvmf_tgt *tgt; 375 int rc = -1; 376 377 req = calloc(1, sizeof(*req)); 378 if (!req) { 379 SPDK_ERRLOG("Memory allocation failed\n"); 380 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 381 "Memory allocation failed"); 382 return; 383 } 384 req->min_cntlid = NVMF_MIN_CNTLID; 385 req->max_cntlid = NVMF_MAX_CNTLID; 386 387 if (spdk_json_decode_object(params, rpc_subsystem_create_decoders, 388 SPDK_COUNTOF(rpc_subsystem_create_decoders), 389 req)) { 390 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 391 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 392 goto cleanup; 393 } 394 395 tgt = spdk_nvmf_get_tgt(req->tgt_name); 396 if (!tgt) { 397 SPDK_ERRLOG("Unable to find target %s\n", req->tgt_name); 398 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 399 "Unable to find target %s", req->tgt_name); 400 goto cleanup; 401 } 402 403 subsystem = spdk_nvmf_subsystem_create(tgt, req->nqn, SPDK_NVMF_SUBTYPE_NVME, 404 req->max_namespaces); 405 if (!subsystem) { 406 SPDK_ERRLOG("Unable to create subsystem %s\n", req->nqn); 407 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 408 "Unable to create subsystem %s", req->nqn); 409 goto cleanup; 410 } 411 412 if (req->serial_number) { 413 if (spdk_nvmf_subsystem_set_sn(subsystem, req->serial_number)) { 414 SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", req->nqn, req->serial_number); 415 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 416 "Invalid SN %s", req->serial_number); 417 goto cleanup; 418 } 419 } 420 421 if (req->model_number) { 422 if (spdk_nvmf_subsystem_set_mn(subsystem, req->model_number)) { 423 SPDK_ERRLOG("Subsystem %s: invalid model number '%s'\n", req->nqn, req->model_number); 424 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 425 "Invalid MN %s", req->model_number); 426 goto cleanup; 427 } 428 } 429 430 spdk_nvmf_subsystem_set_allow_any_host(subsystem, req->allow_any_host); 431 432 spdk_nvmf_subsystem_set_ana_reporting(subsystem, req->ana_reporting); 433 434 if (nvmf_subsystem_set_cntlid_range(subsystem, req->min_cntlid, req->max_cntlid)) { 435 SPDK_ERRLOG("Subsystem %s: invalid cntlid range [%u-%u]\n", req->nqn, req->min_cntlid, 436 req->max_cntlid); 437 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 438 "Invalid cntlid range [%u-%u]", req->min_cntlid, req->max_cntlid); 439 goto cleanup; 440 } 441 442 rc = spdk_nvmf_subsystem_start(subsystem, 443 rpc_nvmf_subsystem_started, 444 request); 445 if (rc) { 446 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 447 "Failed to start subsystem"); 448 } 449 450 cleanup: 451 free(req->nqn); 452 free(req->tgt_name); 453 free(req->serial_number); 454 free(req->model_number); 455 free(req); 456 457 if (rc && subsystem) { 458 spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL); 459 } 460 } 461 SPDK_RPC_REGISTER("nvmf_create_subsystem", rpc_nvmf_create_subsystem, SPDK_RPC_RUNTIME) 462 463 struct rpc_delete_subsystem { 464 char *nqn; 465 char *tgt_name; 466 }; 467 468 static void 469 free_rpc_delete_subsystem(struct rpc_delete_subsystem *r) 470 { 471 free(r->nqn); 472 free(r->tgt_name); 473 } 474 475 static void 476 rpc_nvmf_subsystem_destroy_complete_cb(void *cb_arg) 477 { 478 struct spdk_jsonrpc_request *request = cb_arg; 479 480 spdk_jsonrpc_send_bool_response(request, true); 481 } 482 483 static void 484 rpc_nvmf_subsystem_stopped(struct spdk_nvmf_subsystem *subsystem, 485 void *cb_arg, int status) 486 { 487 struct spdk_jsonrpc_request *request = cb_arg; 488 int rc; 489 490 nvmf_subsystem_remove_all_listeners(subsystem, true); 491 rc = spdk_nvmf_subsystem_destroy(subsystem, rpc_nvmf_subsystem_destroy_complete_cb, request); 492 if (rc) { 493 if (rc == -EINPROGRESS) { 494 /* response will be sent in completion callback */ 495 return; 496 } else { 497 SPDK_ERRLOG("Subsystem destruction failed, rc %d\n", rc); 498 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 499 "Subsystem destruction failed, rc %d", rc); 500 return; 501 } 502 } 503 spdk_jsonrpc_send_bool_response(request, true); 504 } 505 506 static const struct spdk_json_object_decoder rpc_delete_subsystem_decoders[] = { 507 {"nqn", offsetof(struct rpc_delete_subsystem, nqn), spdk_json_decode_string}, 508 {"tgt_name", offsetof(struct rpc_delete_subsystem, tgt_name), spdk_json_decode_string, true}, 509 }; 510 511 static void 512 rpc_nvmf_delete_subsystem(struct spdk_jsonrpc_request *request, 513 const struct spdk_json_val *params) 514 { 515 struct rpc_delete_subsystem req = { 0 }; 516 struct spdk_nvmf_subsystem *subsystem; 517 struct spdk_nvmf_tgt *tgt; 518 int rc; 519 520 if (spdk_json_decode_object(params, rpc_delete_subsystem_decoders, 521 SPDK_COUNTOF(rpc_delete_subsystem_decoders), 522 &req)) { 523 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 524 goto invalid; 525 } 526 527 if (req.nqn == NULL) { 528 SPDK_ERRLOG("missing name param\n"); 529 goto invalid; 530 } 531 532 tgt = spdk_nvmf_get_tgt(req.tgt_name); 533 if (!tgt) { 534 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 535 "Unable to find a target."); 536 goto invalid_custom_response; 537 } 538 539 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, req.nqn); 540 if (!subsystem) { 541 goto invalid; 542 } 543 544 free_rpc_delete_subsystem(&req); 545 546 rc = spdk_nvmf_subsystem_stop(subsystem, 547 rpc_nvmf_subsystem_stopped, 548 request); 549 if (rc == -EBUSY) { 550 SPDK_ERRLOG("Subsystem currently in another state change try again later.\n"); 551 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 552 "Subsystem currently in another state change try again later."); 553 } else if (rc != 0) { 554 SPDK_ERRLOG("Unable to change state on subsystem. rc=%d\n", rc); 555 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 556 "Unable to change state on subsystem. rc=%d", rc); 557 } 558 559 return; 560 561 invalid: 562 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 563 invalid_custom_response: 564 free_rpc_delete_subsystem(&req); 565 } 566 SPDK_RPC_REGISTER("nvmf_delete_subsystem", rpc_nvmf_delete_subsystem, SPDK_RPC_RUNTIME) 567 568 struct rpc_listen_address { 569 char *transport; 570 char *adrfam; 571 char *traddr; 572 char *trsvcid; 573 }; 574 575 static const struct spdk_json_object_decoder rpc_listen_address_decoders[] = { 576 /* NOTE: "transport" is kept for compatibility; new code should use "trtype" */ 577 {"transport", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true}, 578 {"trtype", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string, true}, 579 {"adrfam", offsetof(struct rpc_listen_address, adrfam), spdk_json_decode_string, true}, 580 {"traddr", offsetof(struct rpc_listen_address, traddr), spdk_json_decode_string}, 581 {"trsvcid", offsetof(struct rpc_listen_address, trsvcid), spdk_json_decode_string, true}, 582 }; 583 584 static int 585 decode_rpc_listen_address(const struct spdk_json_val *val, void *out) 586 { 587 struct rpc_listen_address *req = (struct rpc_listen_address *)out; 588 if (spdk_json_decode_object(val, rpc_listen_address_decoders, 589 SPDK_COUNTOF(rpc_listen_address_decoders), 590 req)) { 591 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 592 return -1; 593 } 594 return 0; 595 } 596 597 static void 598 free_rpc_listen_address(struct rpc_listen_address *r) 599 { 600 free(r->transport); 601 free(r->adrfam); 602 free(r->traddr); 603 free(r->trsvcid); 604 } 605 606 enum nvmf_rpc_listen_op { 607 NVMF_RPC_LISTEN_ADD, 608 NVMF_RPC_LISTEN_REMOVE, 609 NVMF_RPC_LISTEN_SET_ANA_STATE, 610 }; 611 612 struct nvmf_rpc_listener_ctx { 613 char *nqn; 614 char *tgt_name; 615 struct spdk_nvmf_tgt *tgt; 616 struct spdk_nvmf_transport *transport; 617 struct spdk_nvmf_subsystem *subsystem; 618 struct rpc_listen_address address; 619 char *ana_state_str; 620 enum spdk_nvme_ana_state ana_state; 621 uint32_t anagrpid; 622 623 struct spdk_jsonrpc_request *request; 624 struct spdk_nvme_transport_id trid; 625 enum nvmf_rpc_listen_op op; 626 bool response_sent; 627 struct spdk_nvmf_listen_opts opts; 628 629 /* Additional options for listener creation. */ 630 struct spdk_nvmf_listener_opts listener_opts; 631 }; 632 633 static const struct spdk_json_object_decoder nvmf_rpc_listener_decoder[] = { 634 {"nqn", offsetof(struct nvmf_rpc_listener_ctx, nqn), spdk_json_decode_string}, 635 {"listen_address", offsetof(struct nvmf_rpc_listener_ctx, address), decode_rpc_listen_address}, 636 {"tgt_name", offsetof(struct nvmf_rpc_listener_ctx, tgt_name), spdk_json_decode_string, true}, 637 {"secure_channel", offsetof(struct nvmf_rpc_listener_ctx, listener_opts.secure_channel), spdk_json_decode_bool, true}, 638 {"ana_state", offsetof(struct nvmf_rpc_listener_ctx, ana_state_str), spdk_json_decode_string, true}, 639 }; 640 641 static void 642 nvmf_rpc_listener_ctx_free(struct nvmf_rpc_listener_ctx *ctx) 643 { 644 free(ctx->nqn); 645 free(ctx->tgt_name); 646 free_rpc_listen_address(&ctx->address); 647 free(ctx->ana_state_str); 648 free(ctx); 649 } 650 651 static void 652 nvmf_rpc_listen_resumed(struct spdk_nvmf_subsystem *subsystem, 653 void *cb_arg, int status) 654 { 655 struct nvmf_rpc_listener_ctx *ctx = cb_arg; 656 struct spdk_jsonrpc_request *request; 657 658 request = ctx->request; 659 if (ctx->response_sent) { 660 /* If an error occurred, the response has already been sent. */ 661 nvmf_rpc_listener_ctx_free(ctx); 662 return; 663 } 664 665 nvmf_rpc_listener_ctx_free(ctx); 666 667 spdk_jsonrpc_send_bool_response(request, true); 668 } 669 670 static void 671 nvmf_rpc_subsystem_listen(void *cb_arg, int status) 672 { 673 struct nvmf_rpc_listener_ctx *ctx = cb_arg; 674 675 if (status) { 676 /* Destroy the listener that we just created. Ignore the error code because 677 * the RPC is failing already anyway. */ 678 spdk_nvmf_tgt_stop_listen(ctx->tgt, &ctx->trid); 679 680 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 681 "Invalid parameters"); 682 ctx->response_sent = true; 683 } 684 685 if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) { 686 if (!ctx->response_sent) { 687 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 688 "Internal error"); 689 } 690 nvmf_rpc_listener_ctx_free(ctx); 691 /* Can't really do anything to recover here - subsystem will remain paused. */ 692 } 693 } 694 static void 695 nvmf_rpc_stop_listen_async_done(void *cb_arg, int status) 696 { 697 struct nvmf_rpc_listener_ctx *ctx = cb_arg; 698 699 if (status) { 700 SPDK_ERRLOG("Unable to stop listener.\n"); 701 spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 702 "error stopping listener: %d", status); 703 ctx->response_sent = true; 704 } 705 706 if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) { 707 if (!ctx->response_sent) { 708 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 709 "Internal error"); 710 } 711 nvmf_rpc_listener_ctx_free(ctx); 712 /* Can't really do anything to recover here - subsystem will remain paused. */ 713 } 714 } 715 716 static void 717 nvmf_rpc_set_ana_state_done(void *cb_arg, int status) 718 { 719 struct nvmf_rpc_listener_ctx *ctx = cb_arg; 720 721 if (status) { 722 SPDK_ERRLOG("Unable to set ANA state.\n"); 723 spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 724 "error setting ANA state: %d", status); 725 ctx->response_sent = true; 726 } 727 728 if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) { 729 if (!ctx->response_sent) { 730 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 731 "Internal error"); 732 } 733 nvmf_rpc_listener_ctx_free(ctx); 734 /* Can't really do anything to recover here - subsystem will remain paused. */ 735 } 736 } 737 738 static void 739 nvmf_rpc_listen_paused(struct spdk_nvmf_subsystem *subsystem, 740 void *cb_arg, int status) 741 { 742 struct nvmf_rpc_listener_ctx *ctx = cb_arg; 743 int rc; 744 745 if (ctx->op == NVMF_RPC_LISTEN_ADD) { 746 if (!nvmf_subsystem_find_listener(subsystem, &ctx->trid)) { 747 rc = spdk_nvmf_tgt_listen_ext(ctx->tgt, &ctx->trid, &ctx->opts); 748 if (rc == 0) { 749 spdk_nvmf_subsystem_add_listener_ext(ctx->subsystem, &ctx->trid, nvmf_rpc_subsystem_listen, ctx, 750 &ctx->listener_opts); 751 return; 752 } 753 754 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 755 "Invalid parameters"); 756 ctx->response_sent = true; 757 } 758 } else if (ctx->op == NVMF_RPC_LISTEN_REMOVE) { 759 rc = spdk_nvmf_subsystem_remove_listener(subsystem, &ctx->trid); 760 if (rc == 0) { 761 spdk_nvmf_transport_stop_listen_async(ctx->transport, &ctx->trid, subsystem, 762 nvmf_rpc_stop_listen_async_done, ctx); 763 return; 764 } 765 SPDK_ERRLOG("Unable to remove listener, rc %d\n", rc); 766 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 767 "Invalid parameters"); 768 ctx->response_sent = true; 769 } else if (ctx->op == NVMF_RPC_LISTEN_SET_ANA_STATE) { 770 nvmf_subsystem_set_ana_state(subsystem, &ctx->trid, ctx->ana_state, ctx->anagrpid, 771 nvmf_rpc_set_ana_state_done, ctx); 772 return; 773 } else { 774 SPDK_UNREACHABLE(); 775 } 776 777 if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_listen_resumed, ctx)) { 778 if (!ctx->response_sent) { 779 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 780 "Internal error"); 781 } 782 nvmf_rpc_listener_ctx_free(ctx); 783 /* Can't really do anything to recover here - subsystem will remain paused. */ 784 } 785 } 786 787 static int 788 rpc_listen_address_to_trid(const struct rpc_listen_address *address, 789 struct spdk_nvme_transport_id *trid) 790 { 791 size_t len; 792 793 memset(trid, 0, sizeof(*trid)); 794 795 if (spdk_nvme_transport_id_populate_trstring(trid, address->transport)) { 796 SPDK_ERRLOG("Invalid transport string: %s\n", address->transport); 797 return -EINVAL; 798 } 799 800 if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, address->transport)) { 801 SPDK_ERRLOG("Invalid transport type: %s\n", address->transport); 802 return -EINVAL; 803 } 804 805 if (address->adrfam) { 806 if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, address->adrfam)) { 807 SPDK_ERRLOG("Invalid adrfam: %s\n", address->adrfam); 808 return -EINVAL; 809 } 810 } else { 811 trid->adrfam = SPDK_NVMF_ADRFAM_IPV4; 812 } 813 814 len = strlen(address->traddr); 815 if (len > sizeof(trid->traddr) - 1) { 816 SPDK_ERRLOG("Transport address longer than %zu characters: %s\n", 817 sizeof(trid->traddr) - 1, address->traddr); 818 return -EINVAL; 819 } 820 memcpy(trid->traddr, address->traddr, len + 1); 821 822 trid->trsvcid[0] = '\0'; 823 if (address->trsvcid) { 824 len = strlen(address->trsvcid); 825 if (len > sizeof(trid->trsvcid) - 1) { 826 SPDK_ERRLOG("Transport service id longer than %zu characters: %s\n", 827 sizeof(trid->trsvcid) - 1, address->trsvcid); 828 return -EINVAL; 829 } 830 memcpy(trid->trsvcid, address->trsvcid, len + 1); 831 } 832 833 return 0; 834 } 835 836 static void 837 rpc_nvmf_subsystem_add_listener(struct spdk_jsonrpc_request *request, 838 const struct spdk_json_val *params) 839 { 840 struct nvmf_rpc_listener_ctx *ctx; 841 struct spdk_nvmf_subsystem *subsystem; 842 struct spdk_nvmf_tgt *tgt; 843 int rc; 844 845 ctx = calloc(1, sizeof(*ctx)); 846 if (!ctx) { 847 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); 848 return; 849 } 850 851 ctx->request = request; 852 853 spdk_nvmf_subsystem_listener_opts_init(&ctx->listener_opts, sizeof(ctx->listener_opts)); 854 855 if (spdk_json_decode_object_relaxed(params, nvmf_rpc_listener_decoder, 856 SPDK_COUNTOF(nvmf_rpc_listener_decoder), 857 ctx)) { 858 SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n"); 859 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 860 nvmf_rpc_listener_ctx_free(ctx); 861 return; 862 } 863 864 tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 865 if (!tgt) { 866 SPDK_ERRLOG("Unable to find a target object.\n"); 867 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 868 "Unable to find a target."); 869 nvmf_rpc_listener_ctx_free(ctx); 870 return; 871 } 872 ctx->tgt = tgt; 873 874 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn); 875 if (!subsystem) { 876 SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); 877 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 878 nvmf_rpc_listener_ctx_free(ctx); 879 return; 880 } 881 882 ctx->subsystem = subsystem; 883 884 if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) { 885 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 886 "Invalid parameters"); 887 nvmf_rpc_listener_ctx_free(ctx); 888 return; 889 } 890 891 ctx->op = NVMF_RPC_LISTEN_ADD; 892 spdk_nvmf_listen_opts_init(&ctx->opts, sizeof(ctx->opts)); 893 ctx->opts.transport_specific = params; 894 if (subsystem->flags.allow_any_host == 1 && ctx->listener_opts.secure_channel == true) { 895 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 896 "Cannot establish secure channel, when 'allow_any_host' is set"); 897 nvmf_rpc_listener_ctx_free(ctx); 898 return; 899 } 900 ctx->opts.secure_channel = ctx->listener_opts.secure_channel; 901 902 if (ctx->ana_state_str) { 903 if (rpc_ana_state_parse(ctx->ana_state_str, &ctx->ana_state)) { 904 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 905 "Invalid parameters"); 906 nvmf_rpc_listener_ctx_free(ctx); 907 return; 908 } 909 ctx->listener_opts.ana_state = ctx->ana_state; 910 } 911 912 rc = spdk_nvmf_subsystem_pause(subsystem, 0, nvmf_rpc_listen_paused, ctx); 913 if (rc != 0) { 914 if (rc == -EBUSY) { 915 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 916 "subsystem busy, retry later.\n"); 917 } else { 918 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 919 } 920 nvmf_rpc_listener_ctx_free(ctx); 921 } 922 } 923 SPDK_RPC_REGISTER("nvmf_subsystem_add_listener", rpc_nvmf_subsystem_add_listener, 924 SPDK_RPC_RUNTIME); 925 926 static void 927 rpc_nvmf_subsystem_remove_listener(struct spdk_jsonrpc_request *request, 928 const struct spdk_json_val *params) 929 { 930 struct nvmf_rpc_listener_ctx *ctx; 931 struct spdk_nvmf_subsystem *subsystem; 932 struct spdk_nvmf_tgt *tgt; 933 int rc; 934 935 ctx = calloc(1, sizeof(*ctx)); 936 if (!ctx) { 937 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); 938 return; 939 } 940 941 ctx->request = request; 942 943 if (spdk_json_decode_object(params, nvmf_rpc_listener_decoder, 944 SPDK_COUNTOF(nvmf_rpc_listener_decoder), 945 ctx)) { 946 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 947 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 948 nvmf_rpc_listener_ctx_free(ctx); 949 return; 950 } 951 952 tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 953 if (!tgt) { 954 SPDK_ERRLOG("Unable to find a target object.\n"); 955 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 956 "Unable to find a target."); 957 nvmf_rpc_listener_ctx_free(ctx); 958 return; 959 } 960 ctx->tgt = tgt; 961 962 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn); 963 if (!subsystem) { 964 SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); 965 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 966 nvmf_rpc_listener_ctx_free(ctx); 967 return; 968 } 969 970 ctx->subsystem = subsystem; 971 972 if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) { 973 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 974 "Invalid parameters"); 975 nvmf_rpc_listener_ctx_free(ctx); 976 return; 977 } 978 979 ctx->transport = spdk_nvmf_tgt_get_transport(tgt, ctx->trid.trstring); 980 if (!ctx->transport) { 981 SPDK_ERRLOG("Unable to find %s transport. The transport must be created first also make sure it is properly registered.\n", 982 ctx->trid.trstring); 983 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 984 "Invalid parameters"); 985 nvmf_rpc_listener_ctx_free(ctx); 986 return; 987 } 988 989 ctx->op = NVMF_RPC_LISTEN_REMOVE; 990 991 rc = spdk_nvmf_subsystem_pause(subsystem, 0, nvmf_rpc_listen_paused, ctx); 992 if (rc != 0) { 993 if (rc == -EBUSY) { 994 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 995 "subsystem busy, retry later.\n"); 996 } else { 997 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 998 } 999 nvmf_rpc_listener_ctx_free(ctx); 1000 } 1001 } 1002 SPDK_RPC_REGISTER("nvmf_subsystem_remove_listener", rpc_nvmf_subsystem_remove_listener, 1003 SPDK_RPC_RUNTIME); 1004 1005 struct nvmf_rpc_referral_ctx { 1006 char *tgt_name; 1007 struct rpc_listen_address address; 1008 bool secure_channel; 1009 }; 1010 1011 static const struct spdk_json_object_decoder nvmf_rpc_referral_decoder[] = { 1012 {"address", offsetof(struct nvmf_rpc_referral_ctx, address), decode_rpc_listen_address}, 1013 {"tgt_name", offsetof(struct nvmf_rpc_referral_ctx, tgt_name), spdk_json_decode_string, true}, 1014 {"secure_channel", offsetof(struct nvmf_rpc_referral_ctx, secure_channel), spdk_json_decode_bool, true}, 1015 }; 1016 1017 static void 1018 nvmf_rpc_referral_ctx_free(struct nvmf_rpc_referral_ctx *ctx) 1019 { 1020 free(ctx->tgt_name); 1021 free_rpc_listen_address(&ctx->address); 1022 } 1023 1024 static void 1025 rpc_nvmf_add_referral(struct spdk_jsonrpc_request *request, 1026 const struct spdk_json_val *params) 1027 { 1028 struct nvmf_rpc_referral_ctx ctx = {}; 1029 struct spdk_nvme_transport_id trid = {}; 1030 struct spdk_nvmf_tgt *tgt; 1031 struct spdk_nvmf_referral_opts opts = {}; 1032 int rc; 1033 1034 if (spdk_json_decode_object_relaxed(params, nvmf_rpc_referral_decoder, 1035 SPDK_COUNTOF(nvmf_rpc_referral_decoder), 1036 &ctx)) { 1037 SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n"); 1038 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1039 nvmf_rpc_referral_ctx_free(&ctx); 1040 return; 1041 } 1042 1043 tgt = spdk_nvmf_get_tgt(ctx.tgt_name); 1044 if (!tgt) { 1045 SPDK_ERRLOG("Unable to find a target object.\n"); 1046 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1047 "Unable to find a target."); 1048 nvmf_rpc_referral_ctx_free(&ctx); 1049 return; 1050 } 1051 1052 if (rpc_listen_address_to_trid(&ctx.address, &trid)) { 1053 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1054 "Invalid parameters"); 1055 nvmf_rpc_referral_ctx_free(&ctx); 1056 return; 1057 } 1058 1059 if ((trid.trtype == SPDK_NVME_TRANSPORT_TCP || 1060 trid.trtype == SPDK_NVME_TRANSPORT_RDMA) && 1061 !strlen(trid.trsvcid)) { 1062 SPDK_ERRLOG("Service ID is required.\n"); 1063 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1064 "Service ID is required."); 1065 nvmf_rpc_referral_ctx_free(&ctx); 1066 return; 1067 } 1068 1069 opts.size = SPDK_SIZEOF(&opts, secure_channel); 1070 opts.trid = trid; 1071 opts.secure_channel = ctx.secure_channel; 1072 1073 rc = spdk_nvmf_tgt_add_referral(tgt, &opts); 1074 if (rc != 0) { 1075 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1076 "Internal error"); 1077 nvmf_rpc_referral_ctx_free(&ctx); 1078 return; 1079 } 1080 1081 nvmf_rpc_referral_ctx_free(&ctx); 1082 1083 spdk_jsonrpc_send_bool_response(request, true); 1084 } 1085 1086 SPDK_RPC_REGISTER("nvmf_discovery_add_referral", rpc_nvmf_add_referral, 1087 SPDK_RPC_RUNTIME); 1088 1089 static void 1090 rpc_nvmf_remove_referral(struct spdk_jsonrpc_request *request, 1091 const struct spdk_json_val *params) 1092 { 1093 struct nvmf_rpc_referral_ctx ctx = {}; 1094 struct spdk_nvme_transport_id trid = {}; 1095 struct spdk_nvmf_referral_opts opts = {}; 1096 struct spdk_nvmf_tgt *tgt; 1097 1098 if (spdk_json_decode_object(params, nvmf_rpc_referral_decoder, 1099 SPDK_COUNTOF(nvmf_rpc_referral_decoder), 1100 &ctx)) { 1101 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1102 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1103 nvmf_rpc_referral_ctx_free(&ctx); 1104 return; 1105 } 1106 1107 tgt = spdk_nvmf_get_tgt(ctx.tgt_name); 1108 if (!tgt) { 1109 SPDK_ERRLOG("Unable to find a target object.\n"); 1110 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1111 "Unable to find a target."); 1112 nvmf_rpc_referral_ctx_free(&ctx); 1113 return; 1114 } 1115 1116 if (rpc_listen_address_to_trid(&ctx.address, &trid)) { 1117 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1118 "Invalid parameters"); 1119 nvmf_rpc_referral_ctx_free(&ctx); 1120 return; 1121 } 1122 1123 opts.size = SPDK_SIZEOF(&opts, secure_channel); 1124 opts.trid = trid; 1125 1126 if (spdk_nvmf_tgt_remove_referral(tgt, &opts)) { 1127 SPDK_ERRLOG("Failed to remove referral.\n"); 1128 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1129 "Unable to remove a referral."); 1130 nvmf_rpc_referral_ctx_free(&ctx); 1131 return; 1132 } 1133 1134 nvmf_rpc_referral_ctx_free(&ctx); 1135 1136 spdk_jsonrpc_send_bool_response(request, true); 1137 } 1138 1139 SPDK_RPC_REGISTER("nvmf_discovery_remove_referral", rpc_nvmf_remove_referral, 1140 SPDK_RPC_RUNTIME); 1141 1142 static void 1143 dump_nvmf_referral(struct spdk_json_write_ctx *w, 1144 struct spdk_nvmf_referral *referral) 1145 { 1146 spdk_json_write_object_begin(w); 1147 1148 spdk_json_write_named_object_begin(w, "address"); 1149 nvmf_transport_listen_dump_trid(&referral->trid, w); 1150 spdk_json_write_object_end(w); 1151 spdk_json_write_named_bool(w, "secure_channel", 1152 referral->entry.treq.secure_channel == SPDK_NVMF_TREQ_SECURE_CHANNEL_REQUIRED); 1153 1154 spdk_json_write_object_end(w); 1155 } 1156 1157 struct rpc_get_referrals_ctx { 1158 char *tgt_name; 1159 }; 1160 1161 static const struct spdk_json_object_decoder rpc_get_referrals_decoders[] = { 1162 {"tgt_name", offsetof(struct rpc_get_referrals_ctx, tgt_name), spdk_json_decode_string, true}, 1163 }; 1164 1165 static void 1166 free_rpc_get_referrals_ctx(struct rpc_get_referrals_ctx *ctx) 1167 { 1168 free(ctx->tgt_name); 1169 free(ctx); 1170 } 1171 1172 static void 1173 rpc_nvmf_get_referrals(struct spdk_jsonrpc_request *request, 1174 const struct spdk_json_val *params) 1175 { 1176 struct rpc_get_referrals_ctx *ctx; 1177 struct spdk_nvmf_tgt *tgt; 1178 struct spdk_json_write_ctx *w; 1179 struct spdk_nvmf_referral *referral; 1180 1181 ctx = calloc(1, sizeof(*ctx)); 1182 if (!ctx) { 1183 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1184 "Out of memory"); 1185 return; 1186 } 1187 1188 if (params) { 1189 if (spdk_json_decode_object(params, rpc_get_referrals_decoders, 1190 SPDK_COUNTOF(rpc_get_referrals_decoders), 1191 ctx)) { 1192 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1193 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1194 "Invalid parameters"); 1195 free_rpc_get_referrals_ctx(ctx); 1196 return; 1197 } 1198 } 1199 1200 tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 1201 if (!tgt) { 1202 SPDK_ERRLOG("Unable to find a target object.\n"); 1203 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1204 "Unable to find a target"); 1205 free_rpc_get_referrals_ctx(ctx); 1206 return; 1207 } 1208 1209 w = spdk_jsonrpc_begin_result(request); 1210 1211 spdk_json_write_array_begin(w); 1212 1213 TAILQ_FOREACH(referral, &tgt->referrals, link) { 1214 dump_nvmf_referral(w, referral); 1215 } 1216 1217 spdk_json_write_array_end(w); 1218 1219 spdk_jsonrpc_end_result(request, w); 1220 1221 free_rpc_get_referrals_ctx(ctx); 1222 } 1223 SPDK_RPC_REGISTER("nvmf_discovery_get_referrals", rpc_nvmf_get_referrals, 1224 SPDK_RPC_RUNTIME); 1225 1226 static const struct spdk_json_object_decoder nvmf_rpc_set_ana_state_decoder[] = { 1227 {"nqn", offsetof(struct nvmf_rpc_listener_ctx, nqn), spdk_json_decode_string}, 1228 {"listen_address", offsetof(struct nvmf_rpc_listener_ctx, address), decode_rpc_listen_address}, 1229 {"ana_state", offsetof(struct nvmf_rpc_listener_ctx, ana_state_str), spdk_json_decode_string}, 1230 {"tgt_name", offsetof(struct nvmf_rpc_listener_ctx, tgt_name), spdk_json_decode_string, true}, 1231 {"anagrpid", offsetof(struct nvmf_rpc_listener_ctx, anagrpid), spdk_json_decode_uint32, true}, 1232 }; 1233 1234 static int 1235 rpc_ana_state_parse(const char *str, enum spdk_nvme_ana_state *ana_state) 1236 { 1237 if (ana_state == NULL || str == NULL) { 1238 return -EINVAL; 1239 } 1240 1241 if (strcasecmp(str, "optimized") == 0) { 1242 *ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE; 1243 } else if (strcasecmp(str, "non_optimized") == 0) { 1244 *ana_state = SPDK_NVME_ANA_NON_OPTIMIZED_STATE; 1245 } else if (strcasecmp(str, "inaccessible") == 0) { 1246 *ana_state = SPDK_NVME_ANA_INACCESSIBLE_STATE; 1247 } else { 1248 return -ENOENT; 1249 } 1250 1251 return 0; 1252 } 1253 1254 static void 1255 rpc_nvmf_subsystem_listener_set_ana_state(struct spdk_jsonrpc_request *request, 1256 const struct spdk_json_val *params) 1257 { 1258 struct nvmf_rpc_listener_ctx *ctx; 1259 struct spdk_nvmf_subsystem *subsystem; 1260 struct spdk_nvmf_tgt *tgt; 1261 1262 ctx = calloc(1, sizeof(*ctx)); 1263 if (!ctx) { 1264 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1265 "Out of memory"); 1266 return; 1267 } 1268 1269 ctx->request = request; 1270 1271 if (spdk_json_decode_object(params, nvmf_rpc_set_ana_state_decoder, 1272 SPDK_COUNTOF(nvmf_rpc_set_ana_state_decoder), 1273 ctx)) { 1274 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1275 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1276 "Invalid parameters"); 1277 nvmf_rpc_listener_ctx_free(ctx); 1278 return; 1279 } 1280 1281 tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 1282 if (!tgt) { 1283 SPDK_ERRLOG("Unable to find a target object.\n"); 1284 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1285 "Unable to find a target.\n"); 1286 nvmf_rpc_listener_ctx_free(ctx); 1287 return; 1288 } 1289 1290 ctx->tgt = tgt; 1291 1292 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn); 1293 if (!subsystem) { 1294 SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); 1295 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1296 "Unable to find subsystem with NQN %s", 1297 ctx->nqn); 1298 nvmf_rpc_listener_ctx_free(ctx); 1299 return; 1300 } 1301 1302 ctx->subsystem = subsystem; 1303 1304 if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) { 1305 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1306 "Invalid parameters"); 1307 nvmf_rpc_listener_ctx_free(ctx); 1308 return; 1309 } 1310 1311 if (rpc_ana_state_parse(ctx->ana_state_str, &ctx->ana_state)) { 1312 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1313 "Invalid parameters"); 1314 nvmf_rpc_listener_ctx_free(ctx); 1315 return; 1316 } 1317 1318 ctx->op = NVMF_RPC_LISTEN_SET_ANA_STATE; 1319 1320 if (spdk_nvmf_subsystem_pause(subsystem, 0, nvmf_rpc_listen_paused, ctx)) { 1321 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1322 "Internal error"); 1323 nvmf_rpc_listener_ctx_free(ctx); 1324 } 1325 } 1326 SPDK_RPC_REGISTER("nvmf_subsystem_listener_set_ana_state", 1327 rpc_nvmf_subsystem_listener_set_ana_state, SPDK_RPC_RUNTIME); 1328 1329 struct spdk_nvmf_ns_params { 1330 char *bdev_name; 1331 char *ptpl_file; 1332 uint32_t nsid; 1333 char nguid[16]; 1334 char eui64[8]; 1335 struct spdk_uuid uuid; 1336 uint32_t anagrpid; 1337 }; 1338 1339 static const struct spdk_json_object_decoder rpc_ns_params_decoders[] = { 1340 {"nsid", offsetof(struct spdk_nvmf_ns_params, nsid), spdk_json_decode_uint32, true}, 1341 {"bdev_name", offsetof(struct spdk_nvmf_ns_params, bdev_name), spdk_json_decode_string}, 1342 {"ptpl_file", offsetof(struct spdk_nvmf_ns_params, ptpl_file), spdk_json_decode_string, true}, 1343 {"nguid", offsetof(struct spdk_nvmf_ns_params, nguid), decode_ns_nguid, true}, 1344 {"eui64", offsetof(struct spdk_nvmf_ns_params, eui64), decode_ns_eui64, true}, 1345 {"uuid", offsetof(struct spdk_nvmf_ns_params, uuid), spdk_json_decode_uuid, true}, 1346 {"anagrpid", offsetof(struct spdk_nvmf_ns_params, anagrpid), spdk_json_decode_uint32, true}, 1347 }; 1348 1349 static int 1350 decode_rpc_ns_params(const struct spdk_json_val *val, void *out) 1351 { 1352 struct spdk_nvmf_ns_params *ns_params = out; 1353 1354 return spdk_json_decode_object(val, rpc_ns_params_decoders, 1355 SPDK_COUNTOF(rpc_ns_params_decoders), 1356 ns_params); 1357 } 1358 1359 struct nvmf_rpc_ns_ctx { 1360 char *nqn; 1361 char *tgt_name; 1362 struct spdk_nvmf_ns_params ns_params; 1363 1364 struct spdk_jsonrpc_request *request; 1365 bool response_sent; 1366 }; 1367 1368 static const struct spdk_json_object_decoder nvmf_rpc_subsystem_ns_decoder[] = { 1369 {"nqn", offsetof(struct nvmf_rpc_ns_ctx, nqn), spdk_json_decode_string}, 1370 {"namespace", offsetof(struct nvmf_rpc_ns_ctx, ns_params), decode_rpc_ns_params}, 1371 {"tgt_name", offsetof(struct nvmf_rpc_ns_ctx, tgt_name), spdk_json_decode_string, true}, 1372 }; 1373 1374 static void 1375 nvmf_rpc_ns_ctx_free(struct nvmf_rpc_ns_ctx *ctx) 1376 { 1377 free(ctx->nqn); 1378 free(ctx->tgt_name); 1379 free(ctx->ns_params.bdev_name); 1380 free(ctx->ns_params.ptpl_file); 1381 free(ctx); 1382 } 1383 1384 static void 1385 nvmf_rpc_ns_failback_resumed(struct spdk_nvmf_subsystem *subsystem, 1386 void *cb_arg, int status) 1387 { 1388 struct nvmf_rpc_ns_ctx *ctx = cb_arg; 1389 struct spdk_jsonrpc_request *request = ctx->request; 1390 1391 if (status) { 1392 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1393 "Unable to add ns, subsystem in invalid state"); 1394 } else { 1395 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1396 "Unable to add ns, subsystem in active state"); 1397 } 1398 1399 nvmf_rpc_ns_ctx_free(ctx); 1400 } 1401 1402 static void 1403 nvmf_rpc_ns_resumed(struct spdk_nvmf_subsystem *subsystem, 1404 void *cb_arg, int status) 1405 { 1406 struct nvmf_rpc_ns_ctx *ctx = cb_arg; 1407 struct spdk_jsonrpc_request *request = ctx->request; 1408 uint32_t nsid = ctx->ns_params.nsid; 1409 bool response_sent = ctx->response_sent; 1410 struct spdk_json_write_ctx *w; 1411 int rc; 1412 1413 /* The case where the call to add the namespace was successful, but the subsystem couldn't be resumed. */ 1414 if (status && !ctx->response_sent) { 1415 rc = spdk_nvmf_subsystem_remove_ns(subsystem, nsid); 1416 if (rc != 0) { 1417 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1418 "Unable to add ns, subsystem in invalid state"); 1419 nvmf_rpc_ns_ctx_free(ctx); 1420 return; 1421 } 1422 1423 rc = spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_ns_failback_resumed, ctx); 1424 if (rc != 0) { 1425 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 1426 nvmf_rpc_ns_ctx_free(ctx); 1427 return; 1428 } 1429 1430 return; 1431 } 1432 1433 nvmf_rpc_ns_ctx_free(ctx); 1434 1435 if (response_sent) { 1436 return; 1437 } 1438 1439 w = spdk_jsonrpc_begin_result(request); 1440 spdk_json_write_uint32(w, nsid); 1441 spdk_jsonrpc_end_result(request, w); 1442 } 1443 1444 static void 1445 nvmf_rpc_ns_paused(struct spdk_nvmf_subsystem *subsystem, 1446 void *cb_arg, int status) 1447 { 1448 struct nvmf_rpc_ns_ctx *ctx = cb_arg; 1449 struct spdk_nvmf_ns_opts ns_opts; 1450 1451 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts)); 1452 ns_opts.nsid = ctx->ns_params.nsid; 1453 1454 SPDK_STATIC_ASSERT(sizeof(ns_opts.nguid) == sizeof(ctx->ns_params.nguid), "size mismatch"); 1455 memcpy(ns_opts.nguid, ctx->ns_params.nguid, sizeof(ns_opts.nguid)); 1456 1457 SPDK_STATIC_ASSERT(sizeof(ns_opts.eui64) == sizeof(ctx->ns_params.eui64), "size mismatch"); 1458 memcpy(ns_opts.eui64, ctx->ns_params.eui64, sizeof(ns_opts.eui64)); 1459 1460 if (!spdk_uuid_is_null(&ctx->ns_params.uuid)) { 1461 ns_opts.uuid = ctx->ns_params.uuid; 1462 } 1463 1464 ns_opts.anagrpid = ctx->ns_params.anagrpid; 1465 1466 ctx->ns_params.nsid = spdk_nvmf_subsystem_add_ns_ext(subsystem, ctx->ns_params.bdev_name, 1467 &ns_opts, sizeof(ns_opts), 1468 ctx->ns_params.ptpl_file); 1469 if (ctx->ns_params.nsid == 0) { 1470 SPDK_ERRLOG("Unable to add namespace\n"); 1471 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1472 "Invalid parameters"); 1473 ctx->response_sent = true; 1474 goto resume; 1475 } 1476 1477 resume: 1478 if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_ns_resumed, ctx)) { 1479 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 1480 nvmf_rpc_ns_ctx_free(ctx); 1481 } 1482 } 1483 1484 static void 1485 rpc_nvmf_subsystem_add_ns(struct spdk_jsonrpc_request *request, 1486 const struct spdk_json_val *params) 1487 { 1488 struct nvmf_rpc_ns_ctx *ctx; 1489 struct spdk_nvmf_subsystem *subsystem; 1490 struct spdk_nvmf_tgt *tgt; 1491 int rc; 1492 1493 ctx = calloc(1, sizeof(*ctx)); 1494 if (!ctx) { 1495 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); 1496 return; 1497 } 1498 1499 if (spdk_json_decode_object(params, nvmf_rpc_subsystem_ns_decoder, 1500 SPDK_COUNTOF(nvmf_rpc_subsystem_ns_decoder), 1501 ctx)) { 1502 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1503 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1504 nvmf_rpc_ns_ctx_free(ctx); 1505 return; 1506 } 1507 1508 ctx->request = request; 1509 ctx->response_sent = false; 1510 1511 tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 1512 if (!tgt) { 1513 SPDK_ERRLOG("Unable to find a target object.\n"); 1514 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1515 "Unable to find a target."); 1516 nvmf_rpc_ns_ctx_free(ctx); 1517 return; 1518 } 1519 1520 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn); 1521 if (!subsystem) { 1522 SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); 1523 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1524 nvmf_rpc_ns_ctx_free(ctx); 1525 return; 1526 } 1527 1528 rc = spdk_nvmf_subsystem_pause(subsystem, ctx->ns_params.nsid, nvmf_rpc_ns_paused, ctx); 1529 if (rc != 0) { 1530 if (rc == -EBUSY) { 1531 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1532 "subsystem busy, retry later.\n"); 1533 } else { 1534 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 1535 } 1536 nvmf_rpc_ns_ctx_free(ctx); 1537 } 1538 } 1539 SPDK_RPC_REGISTER("nvmf_subsystem_add_ns", rpc_nvmf_subsystem_add_ns, SPDK_RPC_RUNTIME) 1540 1541 struct nvmf_rpc_remove_ns_ctx { 1542 char *nqn; 1543 char *tgt_name; 1544 uint32_t nsid; 1545 1546 struct spdk_jsonrpc_request *request; 1547 bool response_sent; 1548 }; 1549 1550 static const struct spdk_json_object_decoder nvmf_rpc_subsystem_remove_ns_decoder[] = { 1551 {"nqn", offsetof(struct nvmf_rpc_remove_ns_ctx, nqn), spdk_json_decode_string}, 1552 {"nsid", offsetof(struct nvmf_rpc_remove_ns_ctx, nsid), spdk_json_decode_uint32}, 1553 {"tgt_name", offsetof(struct nvmf_rpc_remove_ns_ctx, tgt_name), spdk_json_decode_string, true}, 1554 }; 1555 1556 static void 1557 nvmf_rpc_remove_ns_ctx_free(struct nvmf_rpc_remove_ns_ctx *ctx) 1558 { 1559 free(ctx->nqn); 1560 free(ctx->tgt_name); 1561 free(ctx); 1562 } 1563 1564 static void 1565 nvmf_rpc_remove_ns_resumed(struct spdk_nvmf_subsystem *subsystem, 1566 void *cb_arg, int status) 1567 { 1568 struct nvmf_rpc_remove_ns_ctx *ctx = cb_arg; 1569 struct spdk_jsonrpc_request *request = ctx->request; 1570 bool response_sent = ctx->response_sent; 1571 1572 nvmf_rpc_remove_ns_ctx_free(ctx); 1573 1574 if (response_sent) { 1575 return; 1576 } 1577 1578 spdk_jsonrpc_send_bool_response(request, true); 1579 } 1580 1581 static void 1582 nvmf_rpc_remove_ns_paused(struct spdk_nvmf_subsystem *subsystem, 1583 void *cb_arg, int status) 1584 { 1585 struct nvmf_rpc_remove_ns_ctx *ctx = cb_arg; 1586 int ret; 1587 1588 ret = spdk_nvmf_subsystem_remove_ns(subsystem, ctx->nsid); 1589 if (ret < 0) { 1590 SPDK_ERRLOG("Unable to remove namespace ID %u\n", ctx->nsid); 1591 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1592 "Invalid parameters"); 1593 ctx->response_sent = true; 1594 } 1595 1596 if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_remove_ns_resumed, ctx)) { 1597 if (!ctx->response_sent) { 1598 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 1599 } 1600 nvmf_rpc_remove_ns_ctx_free(ctx); 1601 } 1602 } 1603 1604 static void 1605 rpc_nvmf_subsystem_remove_ns(struct spdk_jsonrpc_request *request, 1606 const struct spdk_json_val *params) 1607 { 1608 struct nvmf_rpc_remove_ns_ctx *ctx; 1609 struct spdk_nvmf_subsystem *subsystem; 1610 struct spdk_nvmf_tgt *tgt; 1611 int rc; 1612 1613 ctx = calloc(1, sizeof(*ctx)); 1614 if (!ctx) { 1615 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); 1616 return; 1617 } 1618 1619 if (spdk_json_decode_object(params, nvmf_rpc_subsystem_remove_ns_decoder, 1620 SPDK_COUNTOF(nvmf_rpc_subsystem_remove_ns_decoder), 1621 ctx)) { 1622 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1623 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1624 nvmf_rpc_remove_ns_ctx_free(ctx); 1625 return; 1626 } 1627 1628 tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 1629 if (!tgt) { 1630 SPDK_ERRLOG("Unable to find a target object.\n"); 1631 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1632 "Unable to find a target."); 1633 nvmf_rpc_remove_ns_ctx_free(ctx); 1634 return; 1635 } 1636 1637 ctx->request = request; 1638 ctx->response_sent = false; 1639 1640 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn); 1641 if (!subsystem) { 1642 SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); 1643 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1644 nvmf_rpc_remove_ns_ctx_free(ctx); 1645 return; 1646 } 1647 1648 rc = spdk_nvmf_subsystem_pause(subsystem, ctx->nsid, nvmf_rpc_remove_ns_paused, ctx); 1649 if (rc != 0) { 1650 if (rc == -EBUSY) { 1651 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1652 "subsystem busy, retry later.\n"); 1653 } else { 1654 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 1655 } 1656 nvmf_rpc_remove_ns_ctx_free(ctx); 1657 } 1658 } 1659 SPDK_RPC_REGISTER("nvmf_subsystem_remove_ns", rpc_nvmf_subsystem_remove_ns, SPDK_RPC_RUNTIME) 1660 1661 struct nvmf_rpc_host_ctx { 1662 struct spdk_jsonrpc_request *request; 1663 char *nqn; 1664 char *host; 1665 char *tgt_name; 1666 bool allow_any_host; 1667 }; 1668 1669 static const struct spdk_json_object_decoder nvmf_rpc_subsystem_host_decoder[] = { 1670 {"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string}, 1671 {"host", offsetof(struct nvmf_rpc_host_ctx, host), spdk_json_decode_string}, 1672 {"tgt_name", offsetof(struct nvmf_rpc_host_ctx, tgt_name), spdk_json_decode_string, true}, 1673 }; 1674 1675 static void 1676 nvmf_rpc_host_ctx_free(struct nvmf_rpc_host_ctx *ctx) 1677 { 1678 free(ctx->nqn); 1679 free(ctx->host); 1680 free(ctx->tgt_name); 1681 } 1682 1683 static void 1684 rpc_nvmf_subsystem_add_host(struct spdk_jsonrpc_request *request, 1685 const struct spdk_json_val *params) 1686 { 1687 struct nvmf_rpc_host_ctx ctx = {}; 1688 struct spdk_nvmf_subsystem *subsystem; 1689 struct spdk_nvmf_tgt *tgt; 1690 int rc; 1691 1692 if (spdk_json_decode_object_relaxed(params, nvmf_rpc_subsystem_host_decoder, 1693 SPDK_COUNTOF(nvmf_rpc_subsystem_host_decoder), 1694 &ctx)) { 1695 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1696 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1697 nvmf_rpc_host_ctx_free(&ctx); 1698 return; 1699 } 1700 1701 tgt = spdk_nvmf_get_tgt(ctx.tgt_name); 1702 if (!tgt) { 1703 SPDK_ERRLOG("Unable to find a target object.\n"); 1704 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1705 "Unable to find a target."); 1706 nvmf_rpc_host_ctx_free(&ctx); 1707 return; 1708 } 1709 1710 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx.nqn); 1711 if (!subsystem) { 1712 SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx.nqn); 1713 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1714 nvmf_rpc_host_ctx_free(&ctx); 1715 return; 1716 } 1717 1718 rc = spdk_nvmf_subsystem_add_host(subsystem, ctx.host, params); 1719 if (rc != 0) { 1720 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 1721 nvmf_rpc_host_ctx_free(&ctx); 1722 return; 1723 } 1724 1725 spdk_jsonrpc_send_bool_response(request, true); 1726 nvmf_rpc_host_ctx_free(&ctx); 1727 } 1728 SPDK_RPC_REGISTER("nvmf_subsystem_add_host", rpc_nvmf_subsystem_add_host, SPDK_RPC_RUNTIME) 1729 1730 static void 1731 rpc_nvmf_subsystem_remove_host_done(void *_ctx, int status) 1732 { 1733 struct nvmf_rpc_host_ctx *ctx = _ctx; 1734 1735 spdk_jsonrpc_send_bool_response(ctx->request, true); 1736 nvmf_rpc_host_ctx_free(ctx); 1737 free(ctx); 1738 } 1739 1740 static void 1741 rpc_nvmf_subsystem_remove_host(struct spdk_jsonrpc_request *request, 1742 const struct spdk_json_val *params) 1743 { 1744 struct nvmf_rpc_host_ctx *ctx; 1745 struct spdk_nvmf_subsystem *subsystem; 1746 struct spdk_nvmf_tgt *tgt; 1747 int rc; 1748 1749 ctx = calloc(1, sizeof(*ctx)); 1750 if (ctx == NULL) { 1751 SPDK_ERRLOG("Unable to allocate context to perform RPC\n"); 1752 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); 1753 return; 1754 } 1755 1756 ctx->request = request; 1757 1758 if (spdk_json_decode_object(params, nvmf_rpc_subsystem_host_decoder, 1759 SPDK_COUNTOF(nvmf_rpc_subsystem_host_decoder), 1760 ctx)) { 1761 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1762 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1763 nvmf_rpc_host_ctx_free(ctx); 1764 free(ctx); 1765 return; 1766 } 1767 1768 tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 1769 if (!tgt) { 1770 SPDK_ERRLOG("Unable to find a target object.\n"); 1771 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1772 "Unable to find a target."); 1773 nvmf_rpc_host_ctx_free(ctx); 1774 free(ctx); 1775 return; 1776 } 1777 1778 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn); 1779 if (!subsystem) { 1780 SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); 1781 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1782 nvmf_rpc_host_ctx_free(ctx); 1783 free(ctx); 1784 return; 1785 } 1786 1787 rc = spdk_nvmf_subsystem_remove_host(subsystem, ctx->host); 1788 if (rc != 0) { 1789 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 1790 nvmf_rpc_host_ctx_free(ctx); 1791 free(ctx); 1792 return; 1793 } 1794 1795 rc = spdk_nvmf_subsystem_disconnect_host(subsystem, ctx->host, 1796 rpc_nvmf_subsystem_remove_host_done, 1797 ctx); 1798 if (rc != 0) { 1799 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 1800 nvmf_rpc_host_ctx_free(ctx); 1801 free(ctx); 1802 return; 1803 } 1804 } 1805 SPDK_RPC_REGISTER("nvmf_subsystem_remove_host", rpc_nvmf_subsystem_remove_host, 1806 SPDK_RPC_RUNTIME) 1807 1808 1809 static const struct spdk_json_object_decoder nvmf_rpc_subsystem_any_host_decoder[] = { 1810 {"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string}, 1811 {"allow_any_host", offsetof(struct nvmf_rpc_host_ctx, allow_any_host), spdk_json_decode_bool}, 1812 {"tgt_name", offsetof(struct nvmf_rpc_host_ctx, tgt_name), spdk_json_decode_string, true}, 1813 }; 1814 1815 static void 1816 rpc_nvmf_subsystem_allow_any_host(struct spdk_jsonrpc_request *request, 1817 const struct spdk_json_val *params) 1818 { 1819 struct nvmf_rpc_host_ctx ctx = {}; 1820 struct spdk_nvmf_subsystem *subsystem; 1821 struct spdk_nvmf_tgt *tgt; 1822 int rc; 1823 1824 if (spdk_json_decode_object(params, nvmf_rpc_subsystem_any_host_decoder, 1825 SPDK_COUNTOF(nvmf_rpc_subsystem_any_host_decoder), 1826 &ctx)) { 1827 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1828 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1829 nvmf_rpc_host_ctx_free(&ctx); 1830 return; 1831 } 1832 1833 tgt = spdk_nvmf_get_tgt(ctx.tgt_name); 1834 if (!tgt) { 1835 SPDK_ERRLOG("Unable to find a target object.\n"); 1836 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1837 "Unable to find a target."); 1838 nvmf_rpc_host_ctx_free(&ctx); 1839 return; 1840 } 1841 1842 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx.nqn); 1843 if (!subsystem) { 1844 SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx.nqn); 1845 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1846 nvmf_rpc_host_ctx_free(&ctx); 1847 return; 1848 } 1849 1850 rc = spdk_nvmf_subsystem_set_allow_any_host(subsystem, ctx.allow_any_host); 1851 if (rc != 0) { 1852 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); 1853 nvmf_rpc_host_ctx_free(&ctx); 1854 return; 1855 } 1856 1857 spdk_jsonrpc_send_bool_response(request, true); 1858 nvmf_rpc_host_ctx_free(&ctx); 1859 } 1860 SPDK_RPC_REGISTER("nvmf_subsystem_allow_any_host", rpc_nvmf_subsystem_allow_any_host, 1861 SPDK_RPC_RUNTIME) 1862 1863 struct nvmf_rpc_target_ctx { 1864 char *name; 1865 uint32_t max_subsystems; 1866 char *discovery_filter; 1867 }; 1868 1869 static int 1870 decode_discovery_filter(const struct spdk_json_val *val, void *out) 1871 { 1872 enum spdk_nvmf_tgt_discovery_filter *_filter = (enum spdk_nvmf_tgt_discovery_filter *)out; 1873 enum spdk_nvmf_tgt_discovery_filter filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; 1874 char *tokens = spdk_json_strdup(val); 1875 char *tok; 1876 int rc = -EINVAL; 1877 bool all_specified = false; 1878 1879 if (!tokens) { 1880 return -ENOMEM; 1881 } 1882 1883 tok = strtok(tokens, ","); 1884 while (tok) { 1885 if (strncmp(tok, "match_any", 9) == 0) { 1886 if (filter != SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY) { 1887 goto out; 1888 } 1889 filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY; 1890 all_specified = true; 1891 } else { 1892 if (all_specified) { 1893 goto out; 1894 } 1895 if (strncmp(tok, "transport", 9) == 0) { 1896 filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE; 1897 } else if (strncmp(tok, "address", 7) == 0) { 1898 filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS; 1899 } else if (strncmp(tok, "svcid", 5) == 0) { 1900 filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID; 1901 } else { 1902 SPDK_ERRLOG("Invalid value %s\n", tok); 1903 goto out; 1904 } 1905 } 1906 1907 tok = strtok(NULL, ","); 1908 } 1909 1910 rc = 0; 1911 *_filter = filter; 1912 1913 out: 1914 free(tokens); 1915 1916 return rc; 1917 } 1918 1919 static const struct spdk_json_object_decoder nvmf_rpc_create_target_decoder[] = { 1920 {"name", offsetof(struct nvmf_rpc_target_ctx, name), spdk_json_decode_string}, 1921 {"max_subsystems", offsetof(struct nvmf_rpc_target_ctx, max_subsystems), spdk_json_decode_uint32, true}, 1922 {"discovery_filter", offsetof(struct nvmf_rpc_target_ctx, discovery_filter), decode_discovery_filter, true} 1923 }; 1924 1925 static void 1926 rpc_nvmf_create_target(struct spdk_jsonrpc_request *request, 1927 const struct spdk_json_val *params) 1928 { 1929 struct spdk_nvmf_target_opts opts; 1930 struct nvmf_rpc_target_ctx ctx = {0}; 1931 struct spdk_nvmf_tgt *tgt; 1932 struct spdk_json_write_ctx *w; 1933 1934 /* Decode parameters the first time to get the transport type */ 1935 if (spdk_json_decode_object(params, nvmf_rpc_create_target_decoder, 1936 SPDK_COUNTOF(nvmf_rpc_create_target_decoder), 1937 &ctx)) { 1938 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1939 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1940 goto out; 1941 } 1942 1943 snprintf(opts.name, NVMF_TGT_NAME_MAX_LENGTH, "%s", ctx.name); 1944 opts.max_subsystems = ctx.max_subsystems; 1945 1946 if (spdk_nvmf_get_tgt(opts.name) != NULL) { 1947 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1948 "Target already exists."); 1949 goto out; 1950 } 1951 1952 tgt = spdk_nvmf_tgt_create(&opts); 1953 1954 if (tgt == NULL) { 1955 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1956 "Unable to create the requested target."); 1957 goto out; 1958 } 1959 1960 w = spdk_jsonrpc_begin_result(request); 1961 spdk_json_write_string(w, spdk_nvmf_tgt_get_name(tgt)); 1962 spdk_jsonrpc_end_result(request, w); 1963 out: 1964 free(ctx.name); 1965 free(ctx.discovery_filter); 1966 } 1967 /* private */ SPDK_RPC_REGISTER("nvmf_create_target", rpc_nvmf_create_target, SPDK_RPC_RUNTIME); 1968 1969 static const struct spdk_json_object_decoder nvmf_rpc_destroy_target_decoder[] = { 1970 {"name", offsetof(struct nvmf_rpc_target_ctx, name), spdk_json_decode_string}, 1971 }; 1972 1973 static void 1974 nvmf_rpc_destroy_target_done(void *ctx, int status) 1975 { 1976 struct spdk_jsonrpc_request *request = ctx; 1977 1978 spdk_jsonrpc_send_bool_response(request, true); 1979 } 1980 1981 static void 1982 rpc_nvmf_delete_target(struct spdk_jsonrpc_request *request, 1983 const struct spdk_json_val *params) 1984 { 1985 struct nvmf_rpc_target_ctx ctx = {0}; 1986 struct spdk_nvmf_tgt *tgt; 1987 1988 /* Decode parameters the first time to get the transport type */ 1989 if (spdk_json_decode_object(params, nvmf_rpc_destroy_target_decoder, 1990 SPDK_COUNTOF(nvmf_rpc_destroy_target_decoder), 1991 &ctx)) { 1992 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 1993 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 1994 free(ctx.name); 1995 return; 1996 } 1997 1998 tgt = spdk_nvmf_get_tgt(ctx.name); 1999 2000 if (tgt == NULL) { 2001 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 2002 "The specified target doesn't exist, cannot delete it."); 2003 free(ctx.name); 2004 return; 2005 } 2006 2007 spdk_nvmf_tgt_destroy(tgt, nvmf_rpc_destroy_target_done, request); 2008 free(ctx.name); 2009 } 2010 /* private */ SPDK_RPC_REGISTER("nvmf_delete_target", rpc_nvmf_delete_target, SPDK_RPC_RUNTIME); 2011 2012 static void 2013 rpc_nvmf_get_targets(struct spdk_jsonrpc_request *request, 2014 const struct spdk_json_val *params) 2015 { 2016 struct spdk_json_write_ctx *w; 2017 struct spdk_nvmf_tgt *tgt; 2018 const char *name; 2019 2020 if (params != NULL) { 2021 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 2022 "nvmf_get_targets has no parameters."); 2023 return; 2024 } 2025 2026 w = spdk_jsonrpc_begin_result(request); 2027 spdk_json_write_array_begin(w); 2028 2029 tgt = spdk_nvmf_get_first_tgt(); 2030 2031 while (tgt != NULL) { 2032 name = spdk_nvmf_tgt_get_name(tgt); 2033 spdk_json_write_string(w, name); 2034 tgt = spdk_nvmf_get_next_tgt(tgt); 2035 } 2036 2037 spdk_json_write_array_end(w); 2038 spdk_jsonrpc_end_result(request, w); 2039 } 2040 /* private */ SPDK_RPC_REGISTER("nvmf_get_targets", rpc_nvmf_get_targets, SPDK_RPC_RUNTIME); 2041 2042 struct nvmf_rpc_create_transport_ctx { 2043 char *trtype; 2044 char *tgt_name; 2045 struct spdk_nvmf_transport_opts opts; 2046 struct spdk_jsonrpc_request *request; 2047 struct spdk_nvmf_transport *transport; 2048 int status; 2049 }; 2050 2051 /** 2052 * `max_qpairs_per_ctrlr` represents both admin and IO qpairs, that confuses 2053 * users when they configure a transport using RPC. So it was decided to 2054 * deprecate `max_qpairs_per_ctrlr` RPC parameter and use `max_io_qpairs_per_ctrlr` 2055 * But internal logic remains unchanged and SPDK expects that 2056 * spdk_nvmf_transport_opts::max_qpairs_per_ctrlr includes an admin qpair. 2057 * This function parses the number of IO qpairs and adds +1 for admin qpair. 2058 */ 2059 static int 2060 nvmf_rpc_decode_max_io_qpairs(const struct spdk_json_val *val, void *out) 2061 { 2062 uint16_t *i = out; 2063 int rc; 2064 2065 rc = spdk_json_number_to_uint16(val, i); 2066 if (rc == 0) { 2067 (*i)++; 2068 } 2069 2070 return rc; 2071 } 2072 2073 static const struct spdk_json_object_decoder nvmf_rpc_create_transport_decoder[] = { 2074 { "trtype", offsetof(struct nvmf_rpc_create_transport_ctx, trtype), spdk_json_decode_string}, 2075 { 2076 "max_queue_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_queue_depth), 2077 spdk_json_decode_uint16, true 2078 }, 2079 { 2080 "max_io_qpairs_per_ctrlr", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_qpairs_per_ctrlr), 2081 nvmf_rpc_decode_max_io_qpairs, true 2082 }, 2083 { 2084 "in_capsule_data_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.in_capsule_data_size), 2085 spdk_json_decode_uint32, true 2086 }, 2087 { 2088 "max_io_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_io_size), 2089 spdk_json_decode_uint32, true 2090 }, 2091 { 2092 "io_unit_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.io_unit_size), 2093 spdk_json_decode_uint32, true 2094 }, 2095 { 2096 "max_aq_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_aq_depth), 2097 spdk_json_decode_uint32, true 2098 }, 2099 { 2100 "num_shared_buffers", offsetof(struct nvmf_rpc_create_transport_ctx, opts.num_shared_buffers), 2101 spdk_json_decode_uint32, true 2102 }, 2103 { 2104 "buf_cache_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.buf_cache_size), 2105 spdk_json_decode_uint32, true 2106 }, 2107 { 2108 "dif_insert_or_strip", offsetof(struct nvmf_rpc_create_transport_ctx, opts.dif_insert_or_strip), 2109 spdk_json_decode_bool, true 2110 }, 2111 { 2112 "abort_timeout_sec", offsetof(struct nvmf_rpc_create_transport_ctx, opts.abort_timeout_sec), 2113 spdk_json_decode_uint32, true 2114 }, 2115 { 2116 "zcopy", offsetof(struct nvmf_rpc_create_transport_ctx, opts.zcopy), 2117 spdk_json_decode_bool, true 2118 }, 2119 { 2120 "tgt_name", offsetof(struct nvmf_rpc_create_transport_ctx, tgt_name), 2121 spdk_json_decode_string, true 2122 }, 2123 { 2124 "acceptor_poll_rate", offsetof(struct nvmf_rpc_create_transport_ctx, opts.acceptor_poll_rate), 2125 spdk_json_decode_uint32, true 2126 }, 2127 }; 2128 2129 static void 2130 nvmf_rpc_create_transport_ctx_free(struct nvmf_rpc_create_transport_ctx *ctx) 2131 { 2132 free(ctx->trtype); 2133 free(ctx->tgt_name); 2134 free(ctx); 2135 } 2136 2137 static void 2138 nvmf_rpc_transport_destroy_done_cb(void *cb_arg) 2139 { 2140 struct nvmf_rpc_create_transport_ctx *ctx = cb_arg; 2141 2142 spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2143 "Failed to add transport to tgt.(%d)", ctx->status); 2144 nvmf_rpc_create_transport_ctx_free(ctx); 2145 } 2146 2147 static void 2148 nvmf_rpc_tgt_add_transport_done(void *cb_arg, int status) 2149 { 2150 struct nvmf_rpc_create_transport_ctx *ctx = cb_arg; 2151 2152 if (status) { 2153 SPDK_ERRLOG("Failed to add transport to tgt.(%d)\n", status); 2154 ctx->status = status; 2155 spdk_nvmf_transport_destroy(ctx->transport, nvmf_rpc_transport_destroy_done_cb, ctx); 2156 return; 2157 } 2158 2159 spdk_jsonrpc_send_bool_response(ctx->request, true); 2160 nvmf_rpc_create_transport_ctx_free(ctx); 2161 } 2162 2163 static void 2164 nvmf_rpc_create_transport_done(void *cb_arg, struct spdk_nvmf_transport *transport) 2165 { 2166 struct nvmf_rpc_create_transport_ctx *ctx = cb_arg; 2167 2168 if (!transport) { 2169 SPDK_ERRLOG("Failed to create transport.\n"); 2170 spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2171 "Failed to create transport."); 2172 nvmf_rpc_create_transport_ctx_free(ctx); 2173 return; 2174 } 2175 2176 ctx->transport = transport; 2177 2178 spdk_nvmf_tgt_add_transport(spdk_nvmf_get_tgt(ctx->tgt_name), transport, 2179 nvmf_rpc_tgt_add_transport_done, ctx); 2180 } 2181 2182 static void 2183 rpc_nvmf_create_transport(struct spdk_jsonrpc_request *request, 2184 const struct spdk_json_val *params) 2185 { 2186 struct nvmf_rpc_create_transport_ctx *ctx; 2187 struct spdk_nvmf_tgt *tgt; 2188 int rc; 2189 2190 ctx = calloc(1, sizeof(*ctx)); 2191 if (!ctx) { 2192 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory"); 2193 return; 2194 } 2195 2196 /* Decode parameters the first time to get the transport type */ 2197 if (spdk_json_decode_object_relaxed(params, nvmf_rpc_create_transport_decoder, 2198 SPDK_COUNTOF(nvmf_rpc_create_transport_decoder), 2199 ctx)) { 2200 SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n"); 2201 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 2202 nvmf_rpc_create_transport_ctx_free(ctx); 2203 return; 2204 } 2205 2206 tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 2207 if (!tgt) { 2208 SPDK_ERRLOG("Unable to find a target object.\n"); 2209 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2210 "Unable to find a target."); 2211 nvmf_rpc_create_transport_ctx_free(ctx); 2212 return; 2213 } 2214 2215 /* Initialize all the transport options (based on transport type) and decode the 2216 * parameters again to update any options passed in rpc create transport call. 2217 */ 2218 if (!spdk_nvmf_transport_opts_init(ctx->trtype, &ctx->opts, sizeof(ctx->opts))) { 2219 /* This can happen if user specifies PCIE transport type which isn't valid for 2220 * NVMe-oF. 2221 */ 2222 SPDK_ERRLOG("Invalid transport type '%s'\n", ctx->trtype); 2223 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 2224 "Invalid transport type '%s'", ctx->trtype); 2225 nvmf_rpc_create_transport_ctx_free(ctx); 2226 return; 2227 } 2228 2229 if (spdk_json_decode_object_relaxed(params, nvmf_rpc_create_transport_decoder, 2230 SPDK_COUNTOF(nvmf_rpc_create_transport_decoder), 2231 ctx)) { 2232 SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n"); 2233 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 2234 nvmf_rpc_create_transport_ctx_free(ctx); 2235 return; 2236 } 2237 2238 if (spdk_nvmf_tgt_get_transport(tgt, ctx->trtype)) { 2239 SPDK_ERRLOG("Transport type '%s' already exists\n", ctx->trtype); 2240 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2241 "Transport type '%s' already exists", ctx->trtype); 2242 nvmf_rpc_create_transport_ctx_free(ctx); 2243 return; 2244 } 2245 2246 /* Transport can parse additional params themselves */ 2247 ctx->opts.transport_specific = params; 2248 ctx->request = request; 2249 2250 rc = spdk_nvmf_transport_create_async(ctx->trtype, &ctx->opts, nvmf_rpc_create_transport_done, ctx); 2251 if (rc) { 2252 SPDK_ERRLOG("Transport type '%s' create failed\n", ctx->trtype); 2253 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2254 "Transport type '%s' create failed", ctx->trtype); 2255 nvmf_rpc_create_transport_ctx_free(ctx); 2256 } 2257 } 2258 SPDK_RPC_REGISTER("nvmf_create_transport", rpc_nvmf_create_transport, SPDK_RPC_RUNTIME) 2259 2260 struct rpc_get_transport { 2261 char *trtype; 2262 char *tgt_name; 2263 }; 2264 2265 static const struct spdk_json_object_decoder rpc_get_transport_decoders[] = { 2266 {"trtype", offsetof(struct rpc_get_transport, trtype), spdk_json_decode_string, true}, 2267 {"tgt_name", offsetof(struct rpc_get_transport, tgt_name), spdk_json_decode_string, true}, 2268 }; 2269 2270 static void 2271 rpc_nvmf_get_transports(struct spdk_jsonrpc_request *request, 2272 const struct spdk_json_val *params) 2273 { 2274 struct rpc_get_transport req = { 0 }; 2275 struct spdk_json_write_ctx *w; 2276 struct spdk_nvmf_transport *transport = NULL; 2277 struct spdk_nvmf_tgt *tgt; 2278 2279 if (params) { 2280 if (spdk_json_decode_object(params, rpc_get_transport_decoders, 2281 SPDK_COUNTOF(rpc_get_transport_decoders), 2282 &req)) { 2283 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 2284 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 2285 return; 2286 } 2287 } 2288 2289 tgt = spdk_nvmf_get_tgt(req.tgt_name); 2290 if (!tgt) { 2291 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2292 "Unable to find a target."); 2293 free(req.trtype); 2294 free(req.tgt_name); 2295 return; 2296 } 2297 2298 if (req.trtype) { 2299 transport = spdk_nvmf_tgt_get_transport(tgt, req.trtype); 2300 if (transport == NULL) { 2301 SPDK_ERRLOG("transport '%s' does not exist\n", req.trtype); 2302 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 2303 free(req.trtype); 2304 free(req.tgt_name); 2305 return; 2306 } 2307 } 2308 2309 w = spdk_jsonrpc_begin_result(request); 2310 spdk_json_write_array_begin(w); 2311 2312 if (transport) { 2313 nvmf_transport_dump_opts(transport, w, false); 2314 } else { 2315 for (transport = spdk_nvmf_transport_get_first(tgt); transport != NULL; 2316 transport = spdk_nvmf_transport_get_next(transport)) { 2317 nvmf_transport_dump_opts(transport, w, false); 2318 } 2319 } 2320 2321 spdk_json_write_array_end(w); 2322 spdk_jsonrpc_end_result(request, w); 2323 free(req.trtype); 2324 free(req.tgt_name); 2325 } 2326 SPDK_RPC_REGISTER("nvmf_get_transports", rpc_nvmf_get_transports, SPDK_RPC_RUNTIME) 2327 2328 struct rpc_nvmf_get_stats_ctx { 2329 char *tgt_name; 2330 struct spdk_nvmf_tgt *tgt; 2331 struct spdk_jsonrpc_request *request; 2332 struct spdk_json_write_ctx *w; 2333 }; 2334 2335 static const struct spdk_json_object_decoder rpc_get_stats_decoders[] = { 2336 {"tgt_name", offsetof(struct rpc_nvmf_get_stats_ctx, tgt_name), spdk_json_decode_string, true}, 2337 }; 2338 2339 static void 2340 free_get_stats_ctx(struct rpc_nvmf_get_stats_ctx *ctx) 2341 { 2342 free(ctx->tgt_name); 2343 free(ctx); 2344 } 2345 2346 static void 2347 rpc_nvmf_get_stats_done(struct spdk_io_channel_iter *i, int status) 2348 { 2349 struct rpc_nvmf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(i); 2350 2351 spdk_json_write_array_end(ctx->w); 2352 spdk_json_write_object_end(ctx->w); 2353 spdk_jsonrpc_end_result(ctx->request, ctx->w); 2354 free_get_stats_ctx(ctx); 2355 } 2356 2357 static void 2358 _rpc_nvmf_get_stats(struct spdk_io_channel_iter *i) 2359 { 2360 struct rpc_nvmf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(i); 2361 struct spdk_io_channel *ch; 2362 struct spdk_nvmf_poll_group *group; 2363 2364 ch = spdk_get_io_channel(ctx->tgt); 2365 group = spdk_io_channel_get_ctx(ch); 2366 2367 spdk_nvmf_poll_group_dump_stat(group, ctx->w); 2368 2369 spdk_put_io_channel(ch); 2370 spdk_for_each_channel_continue(i, 0); 2371 } 2372 2373 2374 static void 2375 rpc_nvmf_get_stats(struct spdk_jsonrpc_request *request, 2376 const struct spdk_json_val *params) 2377 { 2378 struct rpc_nvmf_get_stats_ctx *ctx; 2379 2380 ctx = calloc(1, sizeof(*ctx)); 2381 if (!ctx) { 2382 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2383 "Memory allocation error"); 2384 return; 2385 } 2386 ctx->request = request; 2387 2388 if (params) { 2389 if (spdk_json_decode_object(params, rpc_get_stats_decoders, 2390 SPDK_COUNTOF(rpc_get_stats_decoders), 2391 ctx)) { 2392 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 2393 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 2394 free_get_stats_ctx(ctx); 2395 return; 2396 } 2397 } 2398 2399 ctx->tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 2400 if (!ctx->tgt) { 2401 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2402 "Unable to find a target."); 2403 free_get_stats_ctx(ctx); 2404 return; 2405 } 2406 2407 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 2408 spdk_json_write_object_begin(ctx->w); 2409 spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); 2410 spdk_json_write_named_array_begin(ctx->w, "poll_groups"); 2411 2412 spdk_for_each_channel(ctx->tgt, 2413 _rpc_nvmf_get_stats, 2414 ctx, 2415 rpc_nvmf_get_stats_done); 2416 } 2417 2418 SPDK_RPC_REGISTER("nvmf_get_stats", rpc_nvmf_get_stats, SPDK_RPC_RUNTIME) 2419 2420 static void 2421 dump_nvmf_ctrlr(struct spdk_json_write_ctx *w, struct spdk_nvmf_ctrlr *ctrlr) 2422 { 2423 uint32_t count; 2424 2425 spdk_json_write_object_begin(w); 2426 2427 spdk_json_write_named_uint32(w, "cntlid", ctrlr->cntlid); 2428 spdk_json_write_named_string(w, "hostnqn", ctrlr->hostnqn); 2429 spdk_json_write_named_uuid(w, "hostid", &ctrlr->hostid); 2430 2431 count = spdk_bit_array_count_set(ctrlr->qpair_mask); 2432 spdk_json_write_named_uint32(w, "num_io_qpairs", count); 2433 2434 spdk_json_write_object_end(w); 2435 } 2436 2437 static const char * 2438 nvmf_qpair_state_str(enum spdk_nvmf_qpair_state state) 2439 { 2440 switch (state) { 2441 case SPDK_NVMF_QPAIR_UNINITIALIZED: 2442 return "uninitialized"; 2443 case SPDK_NVMF_QPAIR_ACTIVE: 2444 return "active"; 2445 case SPDK_NVMF_QPAIR_DEACTIVATING: 2446 return "deactivating"; 2447 case SPDK_NVMF_QPAIR_ERROR: 2448 return "error"; 2449 default: 2450 return NULL; 2451 } 2452 } 2453 2454 static void 2455 dump_nvmf_qpair(struct spdk_json_write_ctx *w, struct spdk_nvmf_qpair *qpair) 2456 { 2457 struct spdk_nvme_transport_id listen_trid = {}; 2458 2459 spdk_json_write_object_begin(w); 2460 2461 spdk_json_write_named_uint32(w, "cntlid", qpair->ctrlr->cntlid); 2462 spdk_json_write_named_uint32(w, "qid", qpair->qid); 2463 spdk_json_write_named_string(w, "state", nvmf_qpair_state_str(qpair->state)); 2464 2465 if (spdk_nvmf_qpair_get_listen_trid(qpair, &listen_trid) == 0) { 2466 spdk_json_write_named_object_begin(w, "listen_address"); 2467 nvmf_transport_listen_dump_trid(&listen_trid, w); 2468 spdk_json_write_object_end(w); 2469 if (qpair->transport->ops->listen_dump_opts) { 2470 qpair->transport->ops->listen_dump_opts(qpair->transport, &listen_trid, w); 2471 } 2472 } 2473 2474 spdk_json_write_object_end(w); 2475 } 2476 2477 static const char * 2478 nvme_ana_state_str(enum spdk_nvme_ana_state ana_state) 2479 { 2480 switch (ana_state) { 2481 case SPDK_NVME_ANA_OPTIMIZED_STATE: 2482 return "optimized"; 2483 case SPDK_NVME_ANA_NON_OPTIMIZED_STATE: 2484 return "non_optimized"; 2485 case SPDK_NVME_ANA_INACCESSIBLE_STATE: 2486 return "inaccessible"; 2487 case SPDK_NVME_ANA_PERSISTENT_LOSS_STATE: 2488 return "persistent_loss"; 2489 case SPDK_NVME_ANA_CHANGE_STATE: 2490 return "change"; 2491 default: 2492 return NULL; 2493 } 2494 } 2495 2496 static void 2497 dump_nvmf_subsystem_listener(struct spdk_json_write_ctx *w, 2498 struct spdk_nvmf_subsystem_listener *listener) 2499 { 2500 const struct spdk_nvme_transport_id *trid = listener->trid; 2501 uint32_t i; 2502 2503 spdk_json_write_object_begin(w); 2504 2505 spdk_json_write_named_object_begin(w, "address"); 2506 nvmf_transport_listen_dump_trid(trid, w); 2507 spdk_json_write_object_end(w); 2508 2509 if (nvmf_subsystem_get_ana_reporting(listener->subsystem)) { 2510 spdk_json_write_named_array_begin(w, "ana_states"); 2511 for (i = 0; i < listener->subsystem->max_nsid; i++) { 2512 spdk_json_write_object_begin(w); 2513 spdk_json_write_named_uint32(w, "ana_group", i + 1); 2514 spdk_json_write_named_string(w, "ana_state", 2515 nvme_ana_state_str(listener->ana_state[i])); 2516 spdk_json_write_object_end(w); 2517 } 2518 spdk_json_write_array_end(w); 2519 } 2520 2521 spdk_json_write_object_end(w); 2522 } 2523 2524 struct rpc_subsystem_query_ctx { 2525 char *nqn; 2526 char *tgt_name; 2527 struct spdk_nvmf_subsystem *subsystem; 2528 struct spdk_jsonrpc_request *request; 2529 struct spdk_json_write_ctx *w; 2530 }; 2531 2532 static const struct spdk_json_object_decoder rpc_subsystem_query_decoders[] = { 2533 {"nqn", offsetof(struct rpc_subsystem_query_ctx, nqn), spdk_json_decode_string}, 2534 {"tgt_name", offsetof(struct rpc_subsystem_query_ctx, tgt_name), spdk_json_decode_string, true}, 2535 }; 2536 2537 static void 2538 free_rpc_subsystem_query_ctx(struct rpc_subsystem_query_ctx *ctx) 2539 { 2540 free(ctx->nqn); 2541 free(ctx->tgt_name); 2542 free(ctx); 2543 } 2544 2545 static void 2546 rpc_nvmf_get_controllers_paused(struct spdk_nvmf_subsystem *subsystem, 2547 void *cb_arg, int status) 2548 { 2549 struct rpc_subsystem_query_ctx *ctx = cb_arg; 2550 struct spdk_json_write_ctx *w; 2551 struct spdk_nvmf_ctrlr *ctrlr; 2552 2553 w = spdk_jsonrpc_begin_result(ctx->request); 2554 2555 spdk_json_write_array_begin(w); 2556 TAILQ_FOREACH(ctrlr, &ctx->subsystem->ctrlrs, link) { 2557 dump_nvmf_ctrlr(w, ctrlr); 2558 } 2559 spdk_json_write_array_end(w); 2560 2561 spdk_jsonrpc_end_result(ctx->request, w); 2562 2563 if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) { 2564 SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn); 2565 /* FIXME: RPC should fail if resuming the subsystem failed. */ 2566 } 2567 2568 free_rpc_subsystem_query_ctx(ctx); 2569 } 2570 2571 static void 2572 rpc_nvmf_get_qpairs_done(struct spdk_io_channel_iter *i, int status) 2573 { 2574 struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i); 2575 2576 spdk_json_write_array_end(ctx->w); 2577 spdk_jsonrpc_end_result(ctx->request, ctx->w); 2578 2579 if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) { 2580 SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn); 2581 /* FIXME: RPC should fail if resuming the subsystem failed. */ 2582 } 2583 2584 free_rpc_subsystem_query_ctx(ctx); 2585 } 2586 2587 static void 2588 rpc_nvmf_get_qpairs(struct spdk_io_channel_iter *i) 2589 { 2590 struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i); 2591 struct spdk_io_channel *ch; 2592 struct spdk_nvmf_poll_group *group; 2593 struct spdk_nvmf_qpair *qpair; 2594 2595 ch = spdk_io_channel_iter_get_channel(i); 2596 group = spdk_io_channel_get_ctx(ch); 2597 2598 TAILQ_FOREACH(qpair, &group->qpairs, link) { 2599 if (qpair->ctrlr->subsys == ctx->subsystem) { 2600 dump_nvmf_qpair(ctx->w, qpair); 2601 } 2602 } 2603 2604 spdk_for_each_channel_continue(i, 0); 2605 } 2606 2607 static void 2608 rpc_nvmf_get_qpairs_paused(struct spdk_nvmf_subsystem *subsystem, 2609 void *cb_arg, int status) 2610 { 2611 struct rpc_subsystem_query_ctx *ctx = cb_arg; 2612 2613 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 2614 2615 spdk_json_write_array_begin(ctx->w); 2616 2617 spdk_for_each_channel(ctx->subsystem->tgt, 2618 rpc_nvmf_get_qpairs, 2619 ctx, 2620 rpc_nvmf_get_qpairs_done); 2621 } 2622 2623 static void 2624 rpc_nvmf_get_listeners_paused(struct spdk_nvmf_subsystem *subsystem, 2625 void *cb_arg, int status) 2626 { 2627 struct rpc_subsystem_query_ctx *ctx = cb_arg; 2628 struct spdk_json_write_ctx *w; 2629 struct spdk_nvmf_subsystem_listener *listener; 2630 2631 w = spdk_jsonrpc_begin_result(ctx->request); 2632 2633 spdk_json_write_array_begin(w); 2634 2635 for (listener = spdk_nvmf_subsystem_get_first_listener(ctx->subsystem); 2636 listener != NULL; 2637 listener = spdk_nvmf_subsystem_get_next_listener(ctx->subsystem, listener)) { 2638 dump_nvmf_subsystem_listener(w, listener); 2639 } 2640 spdk_json_write_array_end(w); 2641 2642 spdk_jsonrpc_end_result(ctx->request, w); 2643 2644 if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) { 2645 SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn); 2646 /* FIXME: RPC should fail if resuming the subsystem failed. */ 2647 } 2648 2649 free_rpc_subsystem_query_ctx(ctx); 2650 } 2651 2652 static void 2653 _rpc_nvmf_subsystem_query(struct spdk_jsonrpc_request *request, 2654 const struct spdk_json_val *params, 2655 spdk_nvmf_subsystem_state_change_done cb_fn) 2656 { 2657 struct rpc_subsystem_query_ctx *ctx; 2658 struct spdk_nvmf_subsystem *subsystem; 2659 struct spdk_nvmf_tgt *tgt; 2660 2661 ctx = calloc(1, sizeof(*ctx)); 2662 if (!ctx) { 2663 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2664 "Out of memory"); 2665 return; 2666 } 2667 2668 ctx->request = request; 2669 2670 if (spdk_json_decode_object(params, rpc_subsystem_query_decoders, 2671 SPDK_COUNTOF(rpc_subsystem_query_decoders), 2672 ctx)) { 2673 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 2674 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 2675 "Invalid parameters"); 2676 free_rpc_subsystem_query_ctx(ctx); 2677 return; 2678 } 2679 2680 tgt = spdk_nvmf_get_tgt(ctx->tgt_name); 2681 if (!tgt) { 2682 SPDK_ERRLOG("Unable to find a target object.\n"); 2683 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2684 "Unable to find a target"); 2685 free_rpc_subsystem_query_ctx(ctx); 2686 return; 2687 } 2688 2689 subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn); 2690 if (!subsystem) { 2691 SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn); 2692 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 2693 "Invalid parameters"); 2694 free_rpc_subsystem_query_ctx(ctx); 2695 return; 2696 } 2697 2698 ctx->subsystem = subsystem; 2699 2700 if (spdk_nvmf_subsystem_pause(subsystem, 0, cb_fn, ctx)) { 2701 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 2702 "Internal error"); 2703 free_rpc_subsystem_query_ctx(ctx); 2704 return; 2705 } 2706 } 2707 2708 static void 2709 rpc_nvmf_subsystem_get_controllers(struct spdk_jsonrpc_request *request, 2710 const struct spdk_json_val *params) 2711 { 2712 _rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_controllers_paused); 2713 } 2714 SPDK_RPC_REGISTER("nvmf_subsystem_get_controllers", rpc_nvmf_subsystem_get_controllers, 2715 SPDK_RPC_RUNTIME); 2716 2717 static void 2718 rpc_nvmf_subsystem_get_qpairs(struct spdk_jsonrpc_request *request, 2719 const struct spdk_json_val *params) 2720 { 2721 _rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_qpairs_paused); 2722 } 2723 SPDK_RPC_REGISTER("nvmf_subsystem_get_qpairs", rpc_nvmf_subsystem_get_qpairs, SPDK_RPC_RUNTIME); 2724 2725 static void 2726 rpc_nvmf_subsystem_get_listeners(struct spdk_jsonrpc_request *request, 2727 const struct spdk_json_val *params) 2728 { 2729 _rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_listeners_paused); 2730 } 2731 SPDK_RPC_REGISTER("nvmf_subsystem_get_listeners", rpc_nvmf_subsystem_get_listeners, 2732 SPDK_RPC_RUNTIME); 2733