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