4 * Copyright (c) Intel Corporation. All rights reserved.
5 * Copyright (c) 2018 Mellanox Technologies LTD. All rights reserved.
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_conf
*g_spdk_nvmf_tgt_conf
= NULL
;
47 uint32_t g_spdk_nvmf_tgt_max_subsystems
= 0;
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_max_subsystems(struct spdk_conf_section
*sp
,
68 int *deprecated_values
)
70 int tgt_max_subsystems
;
73 tgt_max_subsystems
= spdk_conf_section_get_intval(sp
, "MaxSubsystems");
74 if (tgt_max_subsystems
>= 0) {
75 g_spdk_nvmf_tgt_max_subsystems
= tgt_max_subsystems
;
78 deprecated
= spdk_conf_section_get_intval(sp
, "MaxQueueDepth");
79 if (deprecated
>= 0) {
80 *deprecated_values
= -1;
83 deprecated
= spdk_conf_section_get_intval(sp
, "MaxQueuesPerSession");
84 if (deprecated
>= 0) {
85 *deprecated_values
= -1;
88 deprecated
= spdk_conf_section_get_intval(sp
, "InCapsuleDataSize");
89 if (deprecated
>= 0) {
90 *deprecated_values
= -1;
93 deprecated
= spdk_conf_section_get_intval(sp
, "MaxIOSize");
94 if (deprecated
>= 0) {
95 *deprecated_values
= -1;
98 deprecated
= spdk_conf_section_get_intval(sp
, "IOUnitSize");
99 if (deprecated
>= 0) {
100 *deprecated_values
= -1;
105 spdk_nvmf_read_config_file_tgt_conf(struct spdk_conf_section
*sp
,
106 struct spdk_nvmf_tgt_conf
*conf
)
108 int acceptor_poll_rate
;
110 acceptor_poll_rate
= spdk_conf_section_get_intval(sp
, "AcceptorPollRate");
111 if (acceptor_poll_rate
>= 0) {
112 conf
->acceptor_poll_rate
= acceptor_poll_rate
;
117 spdk_nvmf_parse_tgt_max_subsystems(void)
119 struct spdk_conf_section
*sp
;
120 int deprecated_values
= 0;
122 sp
= spdk_conf_find_section(NULL
, "Nvmf");
124 spdk_nvmf_read_config_file_tgt_max_subsystems(sp
, &deprecated_values
);
127 return deprecated_values
;
130 static struct spdk_nvmf_tgt_conf
*
131 spdk_nvmf_parse_tgt_conf(void)
133 struct spdk_nvmf_tgt_conf
*conf
;
134 struct spdk_conf_section
*sp
;
136 conf
= calloc(1, sizeof(*conf
));
138 SPDK_ERRLOG("calloc() failed for target conf\n");
142 conf
->acceptor_poll_rate
= ACCEPT_TIMEOUT_US
;
143 conf
->conn_sched
= DEFAULT_CONN_SCHED
;
145 sp
= spdk_conf_find_section(NULL
, "Nvmf");
147 spdk_nvmf_read_config_file_tgt_conf(sp
, conf
);
154 spdk_nvmf_parse_nvmf_tgt(void)
157 int using_deprecated_options
;
159 if (!g_spdk_nvmf_tgt_max_subsystems
) {
160 using_deprecated_options
= spdk_nvmf_parse_tgt_max_subsystems();
161 if (using_deprecated_options
< 0) {
162 SPDK_ERRLOG("Deprecated options detected for the NVMe-oF target.\n"
163 "The following options are no longer controlled by the target\n"
164 "and should be set in the transport on a per-transport basis:\n"
165 "MaxQueueDepth, MaxQueuesPerSession, InCapsuleDataSize, MaxIOSize, IOUnitSize\n"
166 "This can be accomplished by setting the options through the create_nvmf_transport RPC.\n"
167 "You may also continue to configure these options in the conf file under each transport.");
171 if (!g_spdk_nvmf_tgt_conf
) {
172 g_spdk_nvmf_tgt_conf
= spdk_nvmf_parse_tgt_conf();
173 if (!g_spdk_nvmf_tgt_conf
) {
174 SPDK_ERRLOG("spdk_nvmf_parse_tgt_conf() failed\n");
179 g_spdk_nvmf_tgt
= spdk_nvmf_tgt_create(g_spdk_nvmf_tgt_max_subsystems
);
181 g_spdk_nvmf_tgt_max_subsystems
= 0;
183 if (!g_spdk_nvmf_tgt
) {
184 SPDK_ERRLOG("spdk_nvmf_tgt_create() failed\n");
188 rc
= spdk_add_nvmf_discovery_subsystem();
190 SPDK_ERRLOG("spdk_add_nvmf_discovery_subsystem failed\n");
198 spdk_nvmf_tgt_listen_done(void *cb_arg
, int status
)
200 /* TODO: Config parsing should wait for this operation to finish. */
203 SPDK_ERRLOG("Failed to listen on transport address\n");
208 spdk_nvmf_parse_subsystem(struct spdk_conf_section
*sp
)
210 const char *nqn
, *mode
;
217 struct spdk_nvmf_subsystem
*subsystem
;
220 nqn
= spdk_conf_section_get_val(sp
, "NQN");
222 SPDK_ERRLOG("Subsystem missing NQN\n");
226 mode
= spdk_conf_section_get_val(sp
, "Mode");
227 lcore
= spdk_conf_section_get_intval(sp
, "Core");
228 num_ns
= spdk_conf_section_get_intval(sp
, "MaxNamespaces");
232 } else if (num_ns
> SPDK_NVMF_MAX_NAMESPACES
) {
233 num_ns
= SPDK_NVMF_MAX_NAMESPACES
;
236 /* Mode is no longer a valid parameter, but print out a nice
237 * message if it exists to inform users.
240 SPDK_NOTICELOG("Mode present in the [Subsystem] section of the config file.\n"
241 "Mode was removed as a valid parameter.\n");
242 if (strcasecmp(mode
, "Virtual") == 0) {
243 SPDK_NOTICELOG("Your mode value is 'Virtual' which is now the only possible mode.\n"
244 "Your configuration file will work as expected.\n");
246 SPDK_NOTICELOG("Please remove Mode from your configuration file.\n");
251 /* Core is no longer a valid parameter, but print out a nice
252 * message if it exists to inform users.
255 SPDK_NOTICELOG("Core present in the [Subsystem] section of the config file.\n"
256 "Core was removed as an option. Subsystems can now run on all available cores.\n");
257 SPDK_NOTICELOG("Please remove Core from your configuration file. Ignoring it and continuing.\n");
260 sn
= spdk_conf_section_get_val(sp
, "SN");
262 SPDK_ERRLOG("Subsystem %s: missing serial number\n", nqn
);
266 subsystem
= spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt
, nqn
, SPDK_NVMF_SUBTYPE_NVME
, num_ns
);
267 if (subsystem
== NULL
) {
271 if (spdk_nvmf_subsystem_set_sn(subsystem
, sn
)) {
272 SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", nqn
, sn
);
273 spdk_nvmf_subsystem_destroy(subsystem
);
278 mn
= spdk_conf_section_get_val(sp
, "MN");
281 "Subsystem %s: missing model number, will use default\n",
286 if (spdk_nvmf_subsystem_set_mn(subsystem
, mn
)) {
287 SPDK_ERRLOG("Subsystem %s: invalid model number '%s'\n", nqn
, mn
);
288 spdk_nvmf_subsystem_destroy(subsystem
);
295 struct spdk_nvmf_ns_opts ns_opts
;
296 struct spdk_bdev
*bdev
;
297 const char *bdev_name
;
298 const char *uuid_str
;
301 bdev_name
= spdk_conf_section_get_nmval(sp
, "Namespace", i
, 0);
306 bdev
= spdk_bdev_get_by_name(bdev_name
);
308 SPDK_ERRLOG("Could not find namespace bdev '%s'\n", bdev_name
);
309 spdk_nvmf_subsystem_destroy(subsystem
);
314 spdk_nvmf_ns_opts_get_defaults(&ns_opts
, sizeof(ns_opts
));
316 nsid_str
= spdk_conf_section_get_nmval(sp
, "Namespace", i
, 1);
319 unsigned long nsid_ul
= strtoul(nsid_str
, &end
, 0);
321 if (*end
!= '\0' || nsid_ul
== 0 || nsid_ul
>= UINT32_MAX
) {
322 SPDK_ERRLOG("Invalid NSID %s\n", nsid_str
);
323 spdk_nvmf_subsystem_destroy(subsystem
);
328 ns_opts
.nsid
= (uint32_t)nsid_ul
;
331 uuid_str
= spdk_conf_section_get_nmval(sp
, "Namespace", i
, 2);
333 if (spdk_uuid_parse(&ns_opts
.uuid
, uuid_str
)) {
334 SPDK_ERRLOG("Invalid UUID %s\n", uuid_str
);
335 spdk_nvmf_subsystem_destroy(subsystem
);
341 if (spdk_nvmf_subsystem_add_ns(subsystem
, bdev
, &ns_opts
, sizeof(ns_opts
), NULL
) == 0) {
342 SPDK_ERRLOG("Unable to add namespace\n");
343 spdk_nvmf_subsystem_destroy(subsystem
);
348 SPDK_INFOLOG(SPDK_LOG_NVMF
, "Attaching block device %s to subsystem %s\n",
349 spdk_bdev_get_name(bdev
), spdk_nvmf_subsystem_get_nqn(subsystem
));
352 /* Parse Listen sections */
354 struct spdk_nvme_transport_id trid
= {0};
355 const char *transport
;
361 transport
= spdk_conf_section_get_nmval(sp
, "Listen", i
, 0);
366 if (spdk_nvme_transport_id_parse_trtype(&trid
.trtype
, transport
)) {
367 SPDK_ERRLOG("Invalid listen address transport type '%s'\n", transport
);
371 address
= spdk_conf_section_get_nmval(sp
, "Listen", i
, 1);
376 address_dup
= strdup(address
);
381 ret
= spdk_parse_ip_addr(address_dup
, &host
, &port
);
383 SPDK_ERRLOG("Unable to parse listen address '%s'\n", address
);
388 if (strchr(host
, ':')) {
389 trid
.adrfam
= SPDK_NVMF_ADRFAM_IPV6
;
391 trid
.adrfam
= SPDK_NVMF_ADRFAM_IPV4
;
394 snprintf(trid
.traddr
, sizeof(trid
.traddr
), "%s", host
);
396 snprintf(trid
.trsvcid
, sizeof(trid
.trsvcid
), "%s", port
);
400 spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt
, &trid
, spdk_nvmf_tgt_listen_done
, NULL
);
402 spdk_nvmf_subsystem_add_listener(subsystem
, &trid
);
405 /* Parse Host sections */
407 const char *host
= spdk_conf_section_get_nval(sp
, "Host", i
);
413 spdk_nvmf_subsystem_add_host(subsystem
, host
);
416 allow_any_host
= spdk_conf_section_get_boolval(sp
, "AllowAnyHost", false);
417 spdk_nvmf_subsystem_set_allow_any_host(subsystem
, allow_any_host
);
420 return (subsystem
!= NULL
);
424 spdk_nvmf_parse_subsystems(void)
427 struct spdk_conf_section
*sp
;
429 sp
= spdk_conf_first_section(NULL
);
431 if (spdk_conf_section_match_prefix(sp
, "Subsystem")) {
432 rc
= spdk_nvmf_parse_subsystem(sp
);
437 sp
= spdk_conf_next_section(sp
);
442 struct spdk_nvmf_parse_transport_ctx
{
443 struct spdk_conf_section
*sp
;
444 spdk_nvmf_parse_conf_done_fn cb_fn
;
447 static void spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx
*ctx
);
450 spdk_nvmf_tgt_add_transport_done(void *cb_arg
, int status
)
452 struct spdk_nvmf_parse_transport_ctx
*ctx
= cb_arg
;
456 SPDK_ERRLOG("Add transport to target failed (%d).\n", status
);
462 /* find next transport */
463 ctx
->sp
= spdk_conf_next_section(ctx
->sp
);
465 if (spdk_conf_section_match_prefix(ctx
->sp
, "Transport")) {
466 spdk_nvmf_parse_transport(ctx
);
469 ctx
->sp
= spdk_conf_next_section(ctx
->sp
);
472 /* done with transports, parse Subsystem sections */
473 rc
= spdk_nvmf_parse_subsystems();
480 spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx
*ctx
)
483 struct spdk_nvmf_transport_opts opts
= { 0 };
484 enum spdk_nvme_transport_type trtype
;
485 struct spdk_nvmf_transport
*transport
;
488 type
= spdk_conf_section_get_val(ctx
->sp
, "Type");
490 SPDK_ERRLOG("Transport missing Type\n");
496 if (spdk_nvme_transport_id_parse_trtype(&trtype
, type
)) {
497 SPDK_ERRLOG("Invalid transport type '%s'\n", type
);
503 if (spdk_nvmf_tgt_get_transport(g_spdk_nvmf_tgt
, trtype
)) {
504 SPDK_ERRLOG("Duplicate transport type '%s'\n", type
);
510 if (!spdk_nvmf_transport_opts_init(trtype
, &opts
)) {
516 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxQueueDepth");
518 opts
.max_queue_depth
= val
;
520 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxQueuesPerSession");
522 opts
.max_qpairs_per_ctrlr
= val
;
524 val
= spdk_conf_section_get_intval(ctx
->sp
, "InCapsuleDataSize");
526 opts
.in_capsule_data_size
= val
;
528 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxIOSize");
530 opts
.max_io_size
= val
;
532 val
= spdk_conf_section_get_intval(ctx
->sp
, "IOUnitSize");
534 opts
.io_unit_size
= val
;
536 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxAQDepth");
538 opts
.max_aq_depth
= val
;
540 val
= spdk_conf_section_get_intval(ctx
->sp
, "NumSharedBuffers");
542 opts
.num_shared_buffers
= val
;
544 val
= spdk_conf_section_get_intval(ctx
->sp
, "BufCacheSize");
546 opts
.buf_cache_size
= val
;
549 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxSRQDepth");
551 if (trtype
== SPDK_NVME_TRANSPORT_RDMA
) {
552 opts
.max_srq_depth
= val
;
554 SPDK_ERRLOG("MaxSRQDepth is relevant only for RDMA transport '%s'\n", type
);
561 transport
= spdk_nvmf_transport_create(trtype
, &opts
);
563 spdk_nvmf_tgt_add_transport(g_spdk_nvmf_tgt
, transport
, spdk_nvmf_tgt_add_transport_done
, ctx
);
572 spdk_nvmf_parse_transports(spdk_nvmf_parse_conf_done_fn cb_fn
)
574 struct spdk_nvmf_parse_transport_ctx
*ctx
;
576 ctx
= calloc(1, sizeof(struct spdk_nvmf_parse_transport_ctx
));
578 SPDK_ERRLOG("Failed alloc of context memory for parse transports\n");
583 ctx
->sp
= spdk_conf_first_section(NULL
);
584 if (ctx
->sp
== NULL
) {
591 while (ctx
->sp
!= NULL
) {
592 if (spdk_conf_section_match_prefix(ctx
->sp
, "Transport")) {
593 spdk_nvmf_parse_transport(ctx
);
596 ctx
->sp
= spdk_conf_next_section(ctx
->sp
);
599 /* if we get here, there are no transports defined in conf file */
606 spdk_nvmf_parse_conf(spdk_nvmf_parse_conf_done_fn cb_fn
)
611 SPDK_ERRLOG("Callback function is NULL\n");
616 rc
= spdk_nvmf_parse_nvmf_tgt();
621 /* Transport sections */
622 rc
= spdk_nvmf_parse_transports(cb_fn
);