4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "event_nvmf.h"
36 #include "spdk/conf.h"
38 #include "spdk/bdev.h"
39 #include "spdk/nvme.h"
40 #include "spdk/nvmf.h"
41 #include "spdk/string.h"
42 #include "spdk/util.h"
44 #define SPDK_NVMF_MAX_NAMESPACES (1 << 14)
46 struct spdk_nvmf_tgt_opts
*g_spdk_nvmf_tgt_opts
= NULL
;
47 struct spdk_nvmf_tgt_conf
*g_spdk_nvmf_tgt_conf
= NULL
;
50 spdk_add_nvmf_discovery_subsystem(void)
52 struct spdk_nvmf_subsystem
*subsystem
;
54 subsystem
= spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt
, SPDK_NVMF_DISCOVERY_NQN
,
55 SPDK_NVMF_SUBTYPE_DISCOVERY
, 0);
56 if (subsystem
== NULL
) {
57 SPDK_ERRLOG("Failed creating discovery nvmf library subsystem\n");
61 spdk_nvmf_subsystem_set_allow_any_host(subsystem
, true);
67 spdk_nvmf_read_config_file_tgt_opts(struct spdk_conf_section
*sp
,
68 struct spdk_nvmf_tgt_opts
*opts
)
71 int max_queues_per_sess
;
72 int in_capsule_data_size
;
76 max_queue_depth
= spdk_conf_section_get_intval(sp
, "MaxQueueDepth");
77 if (max_queue_depth
>= 0) {
78 opts
->max_queue_depth
= max_queue_depth
;
81 max_queues_per_sess
= spdk_conf_section_get_intval(sp
, "MaxQueuesPerSession");
82 if (max_queues_per_sess
>= 0) {
83 opts
->max_qpairs_per_ctrlr
= max_queues_per_sess
;
86 in_capsule_data_size
= spdk_conf_section_get_intval(sp
, "InCapsuleDataSize");
87 if (in_capsule_data_size
>= 0) {
88 opts
->in_capsule_data_size
= in_capsule_data_size
;
91 max_io_size
= spdk_conf_section_get_intval(sp
, "MaxIOSize");
92 if (max_io_size
>= 0) {
93 opts
->max_io_size
= max_io_size
;
96 io_unit_size
= spdk_conf_section_get_intval(sp
, "IOUnitSize");
97 if (io_unit_size
>= 0) {
98 opts
->io_unit_size
= io_unit_size
;
103 spdk_nvmf_read_config_file_tgt_conf(struct spdk_conf_section
*sp
,
104 struct spdk_nvmf_tgt_conf
*conf
)
106 int acceptor_poll_rate
;
108 acceptor_poll_rate
= spdk_conf_section_get_intval(sp
, "AcceptorPollRate");
109 if (acceptor_poll_rate
>= 0) {
110 conf
->acceptor_poll_rate
= acceptor_poll_rate
;
114 static struct spdk_nvmf_tgt_opts
*
115 spdk_nvmf_parse_tgt_opts(void)
117 struct spdk_nvmf_tgt_opts
*opts
;
118 struct spdk_conf_section
*sp
;
120 opts
= calloc(1, sizeof(*opts
));
122 SPDK_ERRLOG("calloc() failed for target options\n");
126 spdk_nvmf_tgt_opts_init(opts
);
128 sp
= spdk_conf_find_section(NULL
, "Nvmf");
130 spdk_nvmf_read_config_file_tgt_opts(sp
, opts
);
136 static struct spdk_nvmf_tgt_conf
*
137 spdk_nvmf_parse_tgt_conf(void)
139 struct spdk_nvmf_tgt_conf
*conf
;
140 struct spdk_conf_section
*sp
;
142 conf
= calloc(1, sizeof(*conf
));
144 SPDK_ERRLOG("calloc() failed for target conf\n");
148 conf
->acceptor_poll_rate
= ACCEPT_TIMEOUT_US
;
149 conf
->conn_sched
= DEFAULT_CONN_SCHED
;
151 sp
= spdk_conf_find_section(NULL
, "Nvmf");
153 spdk_nvmf_read_config_file_tgt_conf(sp
, conf
);
160 spdk_nvmf_parse_nvmf_tgt(void)
164 if (!g_spdk_nvmf_tgt_opts
) {
165 g_spdk_nvmf_tgt_opts
= spdk_nvmf_parse_tgt_opts();
166 if (!g_spdk_nvmf_tgt_opts
) {
167 SPDK_ERRLOG("spdk_nvmf_parse_tgt_opts() failed\n");
172 if (!g_spdk_nvmf_tgt_conf
) {
173 g_spdk_nvmf_tgt_conf
= spdk_nvmf_parse_tgt_conf();
174 if (!g_spdk_nvmf_tgt_conf
) {
175 SPDK_ERRLOG("spdk_nvmf_parse_tgt_conf() failed\n");
180 g_spdk_nvmf_tgt
= spdk_nvmf_tgt_create(g_spdk_nvmf_tgt_opts
);
182 free(g_spdk_nvmf_tgt_opts
);
183 g_spdk_nvmf_tgt_opts
= NULL
;
185 if (!g_spdk_nvmf_tgt
) {
186 SPDK_ERRLOG("spdk_nvmf_tgt_create() failed\n");
190 rc
= spdk_add_nvmf_discovery_subsystem();
192 SPDK_ERRLOG("spdk_add_nvmf_discovery_subsystem failed\n");
200 spdk_nvmf_tgt_listen_done(void *cb_arg
, int status
)
202 /* TODO: Config parsing should wait for this operation to finish. */
205 SPDK_ERRLOG("Failed to listen on transport address\n");
210 spdk_nvmf_parse_subsystem(struct spdk_conf_section
*sp
)
212 const char *nqn
, *mode
;
218 struct spdk_nvmf_subsystem
*subsystem
;
221 nqn
= spdk_conf_section_get_val(sp
, "NQN");
223 SPDK_ERRLOG("Subsystem missing NQN\n");
227 mode
= spdk_conf_section_get_val(sp
, "Mode");
228 lcore
= spdk_conf_section_get_intval(sp
, "Core");
229 num_ns
= spdk_conf_section_get_intval(sp
, "MaxNamespaces");
233 } else if (num_ns
> SPDK_NVMF_MAX_NAMESPACES
) {
234 num_ns
= SPDK_NVMF_MAX_NAMESPACES
;
237 /* Mode is no longer a valid parameter, but print out a nice
238 * message if it exists to inform users.
241 SPDK_NOTICELOG("Mode present in the [Subsystem] section of the config file.\n"
242 "Mode was removed as a valid parameter.\n");
243 if (strcasecmp(mode
, "Virtual") == 0) {
244 SPDK_NOTICELOG("Your mode value is 'Virtual' which is now the only possible mode.\n"
245 "Your configuration file will work as expected.\n");
247 SPDK_NOTICELOG("Please remove Mode from your configuration file.\n");
252 /* Core is no longer a valid parameter, but print out a nice
253 * message if it exists to inform users.
256 SPDK_NOTICELOG("Core present in the [Subsystem] section of the config file.\n"
257 "Core was removed as an option. Subsystems can now run on all available cores.\n");
258 SPDK_NOTICELOG("Please remove Core from your configuration file. Ignoring it and continuing.\n");
261 sn
= spdk_conf_section_get_val(sp
, "SN");
263 SPDK_ERRLOG("Subsystem %s: missing serial number\n", nqn
);
267 subsystem
= spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt
, nqn
, SPDK_NVMF_SUBTYPE_NVME
, num_ns
);
268 if (subsystem
== NULL
) {
272 if (spdk_nvmf_subsystem_set_sn(subsystem
, sn
)) {
273 SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", nqn
, sn
);
274 spdk_nvmf_subsystem_destroy(subsystem
);
280 struct spdk_nvmf_ns_opts ns_opts
;
281 struct spdk_bdev
*bdev
;
282 const char *bdev_name
;
283 const char *uuid_str
;
286 bdev_name
= spdk_conf_section_get_nmval(sp
, "Namespace", i
, 0);
291 bdev
= spdk_bdev_get_by_name(bdev_name
);
293 SPDK_ERRLOG("Could not find namespace bdev '%s'\n", bdev_name
);
294 spdk_nvmf_subsystem_destroy(subsystem
);
299 spdk_nvmf_ns_opts_get_defaults(&ns_opts
, sizeof(ns_opts
));
301 nsid_str
= spdk_conf_section_get_nmval(sp
, "Namespace", i
, 1);
304 unsigned long nsid_ul
= strtoul(nsid_str
, &end
, 0);
306 if (*end
!= '\0' || nsid_ul
== 0 || nsid_ul
>= UINT32_MAX
) {
307 SPDK_ERRLOG("Invalid NSID %s\n", nsid_str
);
308 spdk_nvmf_subsystem_destroy(subsystem
);
313 ns_opts
.nsid
= (uint32_t)nsid_ul
;
316 uuid_str
= spdk_conf_section_get_nmval(sp
, "Namespace", i
, 2);
318 if (spdk_uuid_parse(&ns_opts
.uuid
, uuid_str
)) {
319 SPDK_ERRLOG("Invalid UUID %s\n", uuid_str
);
320 spdk_nvmf_subsystem_destroy(subsystem
);
326 if (spdk_nvmf_subsystem_add_ns(subsystem
, bdev
, &ns_opts
, sizeof(ns_opts
)) == 0) {
327 SPDK_ERRLOG("Unable to add namespace\n");
328 spdk_nvmf_subsystem_destroy(subsystem
);
333 SPDK_INFOLOG(SPDK_LOG_NVMF
, "Attaching block device %s to subsystem %s\n",
334 spdk_bdev_get_name(bdev
), spdk_nvmf_subsystem_get_nqn(subsystem
));
337 /* Parse Listen sections */
339 struct spdk_nvme_transport_id trid
= {0};
340 const char *transport
;
346 transport
= spdk_conf_section_get_nmval(sp
, "Listen", i
, 0);
351 if (spdk_nvme_transport_id_parse_trtype(&trid
.trtype
, transport
)) {
352 SPDK_ERRLOG("Invalid listen address transport type '%s'\n", transport
);
356 address
= spdk_conf_section_get_nmval(sp
, "Listen", i
, 1);
361 address_dup
= strdup(address
);
366 ret
= spdk_parse_ip_addr(address_dup
, &host
, &port
);
368 SPDK_ERRLOG("Unable to parse listen address '%s'\n", address
);
373 if (strchr(host
, ':')) {
374 trid
.adrfam
= SPDK_NVMF_ADRFAM_IPV6
;
376 trid
.adrfam
= SPDK_NVMF_ADRFAM_IPV4
;
379 snprintf(trid
.traddr
, sizeof(trid
.traddr
), "%s", host
);
381 snprintf(trid
.trsvcid
, sizeof(trid
.trsvcid
), "%s", port
);
385 spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt
, &trid
, spdk_nvmf_tgt_listen_done
, NULL
);
387 spdk_nvmf_subsystem_add_listener(subsystem
, &trid
);
390 /* Parse Host sections */
392 const char *host
= spdk_conf_section_get_nval(sp
, "Host", i
);
398 spdk_nvmf_subsystem_add_host(subsystem
, host
);
401 allow_any_host
= spdk_conf_section_get_boolval(sp
, "AllowAnyHost", false);
402 spdk_nvmf_subsystem_set_allow_any_host(subsystem
, allow_any_host
);
405 return (subsystem
!= NULL
);
409 spdk_nvmf_parse_subsystems(void)
412 struct spdk_conf_section
*sp
;
414 sp
= spdk_conf_first_section(NULL
);
416 if (spdk_conf_section_match_prefix(sp
, "Subsystem")) {
417 rc
= spdk_nvmf_parse_subsystem(sp
);
422 sp
= spdk_conf_next_section(sp
);
427 struct spdk_nvmf_parse_transport_ctx
{
428 struct spdk_conf_section
*sp
;
429 spdk_nvmf_parse_conf_done_fn cb_fn
;
432 static void spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx
*ctx
);
435 spdk_nvmf_tgt_add_transport_done(void *cb_arg
, int status
)
437 struct spdk_nvmf_parse_transport_ctx
*ctx
= cb_arg
;
441 SPDK_ERRLOG("Add transport to target failed (%d).\n", status
);
447 /* find next transport */
448 ctx
->sp
= spdk_conf_next_section(ctx
->sp
);
450 if (spdk_conf_section_match_prefix(ctx
->sp
, "Transport")) {
451 spdk_nvmf_parse_transport(ctx
);
454 ctx
->sp
= spdk_conf_next_section(ctx
->sp
);
457 /* done with transports, parse Subsystem sections */
458 rc
= spdk_nvmf_parse_subsystems();
465 spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx
*ctx
)
468 struct spdk_nvmf_transport_opts opts
= { 0 };
469 enum spdk_nvme_transport_type trtype
;
470 struct spdk_nvmf_transport
*transport
;
473 type
= spdk_conf_section_get_val(ctx
->sp
, "Type");
475 SPDK_ERRLOG("Transport missing Type\n");
481 if (spdk_nvme_transport_id_parse_trtype(&trtype
, type
)) {
482 SPDK_ERRLOG("Invalid transport type '%s'\n", type
);
488 if (spdk_nvmf_tgt_get_transport(g_spdk_nvmf_tgt
, trtype
)) {
489 SPDK_ERRLOG("Duplicate transport type '%s'\n", type
);
495 if (!spdk_nvmf_transport_opts_init(trtype
, &opts
)) {
501 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxQueueDepth");
503 opts
.max_queue_depth
= val
;
505 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxQueuesPerSession");
507 opts
.max_qpairs_per_ctrlr
= val
;
509 val
= spdk_conf_section_get_intval(ctx
->sp
, "InCapsuleDataSize");
511 opts
.in_capsule_data_size
= val
;
513 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxIOSize");
515 opts
.max_io_size
= val
;
517 val
= spdk_conf_section_get_intval(ctx
->sp
, "IOUnitSize");
519 opts
.io_unit_size
= val
;
521 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxAQDepth");
523 opts
.max_aq_depth
= val
;
526 transport
= spdk_nvmf_transport_create(trtype
, &opts
);
528 spdk_nvmf_tgt_add_transport(g_spdk_nvmf_tgt
, transport
, spdk_nvmf_tgt_add_transport_done
, ctx
);
537 spdk_nvmf_parse_transports(spdk_nvmf_parse_conf_done_fn cb_fn
)
539 struct spdk_nvmf_parse_transport_ctx
*ctx
;
541 ctx
= calloc(1, sizeof(struct spdk_nvmf_parse_transport_ctx
));
543 SPDK_ERRLOG("Failed alloc of context memory for parse transports\n");
548 ctx
->sp
= spdk_conf_first_section(NULL
);
549 while (ctx
->sp
!= NULL
) {
550 if (spdk_conf_section_match_prefix(ctx
->sp
, "Transport")) {
551 spdk_nvmf_parse_transport(ctx
);
554 ctx
->sp
= spdk_conf_next_section(ctx
->sp
);
557 /* if we get here, there are no transports defined in conf file */
559 cb_fn(spdk_nvmf_parse_subsystems());
565 spdk_nvmf_parse_conf(spdk_nvmf_parse_conf_done_fn cb_fn
)
570 SPDK_ERRLOG("Callback function is NULL\n");
575 rc
= spdk_nvmf_parse_nvmf_tgt();
580 /* Transport sections */
581 rc
= spdk_nvmf_parse_transports(cb_fn
);