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 nvmf_add_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 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 nvmf_read_config_file_tgt_conf(struct spdk_conf_section
*sp
,
106 struct spdk_nvmf_tgt_conf
*conf
)
108 int acceptor_poll_rate
;
109 const char *conn_scheduler
;
112 acceptor_poll_rate
= spdk_conf_section_get_intval(sp
, "AcceptorPollRate");
113 if (acceptor_poll_rate
>= 0) {
114 conf
->acceptor_poll_rate
= acceptor_poll_rate
;
117 conn_scheduler
= spdk_conf_section_get_val(sp
, "ConnectionScheduler");
119 if (conn_scheduler
) {
120 SPDK_NOTICELOG("The ConnectionScheduler option is no longer valid. Ignoring it.\n");
123 conf
->admin_passthru
.identify_ctrlr
= spdk_conf_section_get_boolval(sp
,
124 "AdminCmdPassthruIdentifyCtrlr", false);
130 nvmf_parse_tgt_max_subsystems(void)
132 struct spdk_conf_section
*sp
;
133 int deprecated_values
= 0;
135 sp
= spdk_conf_find_section(NULL
, "Nvmf");
137 nvmf_read_config_file_tgt_max_subsystems(sp
, &deprecated_values
);
140 return deprecated_values
;
143 static struct spdk_nvmf_tgt_conf
*
144 nvmf_parse_tgt_conf(void)
146 struct spdk_nvmf_tgt_conf
*conf
;
147 struct spdk_conf_section
*sp
;
150 conf
= calloc(1, sizeof(*conf
));
152 SPDK_ERRLOG("calloc() failed for target conf\n");
156 conf
->acceptor_poll_rate
= ACCEPT_TIMEOUT_US
;
157 conf
->admin_passthru
.identify_ctrlr
= false;
159 sp
= spdk_conf_find_section(NULL
, "Nvmf");
161 rc
= nvmf_read_config_file_tgt_conf(sp
, conf
);
172 nvmf_parse_nvmf_tgt(void)
175 int using_deprecated_options
;
176 struct spdk_nvmf_target_opts opts
= {
181 if (!g_spdk_nvmf_tgt_max_subsystems
) {
182 using_deprecated_options
= nvmf_parse_tgt_max_subsystems();
183 if (using_deprecated_options
< 0) {
184 SPDK_ERRLOG("Deprecated options detected for the NVMe-oF target.\n"
185 "The following options are no longer controlled by the target\n"
186 "and should be set in the transport on a per-transport basis:\n"
187 "MaxQueueDepth, MaxQueuesPerSession, InCapsuleDataSize, MaxIOSize, IOUnitSize\n"
188 "This can be accomplished by setting the options through the create_nvmf_transport RPC.\n"
189 "You may also continue to configure these options in the conf file under each transport.");
193 if (!g_spdk_nvmf_tgt_conf
) {
194 g_spdk_nvmf_tgt_conf
= nvmf_parse_tgt_conf();
195 if (!g_spdk_nvmf_tgt_conf
) {
196 SPDK_ERRLOG("nvmf_parse_tgt_conf() failed\n");
201 opts
.max_subsystems
= g_spdk_nvmf_tgt_max_subsystems
;
202 g_spdk_nvmf_tgt
= spdk_nvmf_tgt_create(&opts
);
204 g_spdk_nvmf_tgt_max_subsystems
= 0;
206 if (!g_spdk_nvmf_tgt
) {
207 SPDK_ERRLOG("spdk_nvmf_tgt_create() failed\n");
211 rc
= nvmf_add_discovery_subsystem();
213 SPDK_ERRLOG("nvmf_add_discovery_subsystem failed\n");
221 nvmf_tgt_parse_listen_ip_addr(char *address
,
222 struct spdk_nvme_transport_id
*trid
)
227 if (spdk_parse_ip_addr(address
, &host
, &port
) < 0) {
228 SPDK_ERRLOG("Unable to parse listen address '%s'\n", address
);
232 if (strchr(host
, ':')) {
233 trid
->adrfam
= SPDK_NVMF_ADRFAM_IPV6
;
235 trid
->adrfam
= SPDK_NVMF_ADRFAM_IPV4
;
238 snprintf(trid
->traddr
, sizeof(trid
->traddr
), "%s", host
);
240 snprintf(trid
->trsvcid
, sizeof(trid
->trsvcid
), "%s", port
);
247 nvmf_tgt_parse_listen_fc_addr(const char *address
,
248 struct spdk_nvme_transport_id
*trid
)
250 /* transport address format and requirements,
251 * "nn-0xWWNN:pn-0xWWPN" - size equals 43 bytes and is required to
252 * contain 'nn' and 'pn'.
254 if (strlen(address
) != 43 || strncmp(address
, "nn-0x", 5) ||
255 strncmp(&address
[21], ":pn-0x", 6)) {
256 SPDK_ERRLOG("Unable to parse fc address '%s'\n", address
);
260 trid
->adrfam
= SPDK_NVMF_ADRFAM_FC
;
261 snprintf(trid
->trsvcid
, sizeof(trid
->trsvcid
), "none");
262 snprintf(trid
->traddr
, sizeof(trid
->traddr
), "%s", address
);
268 nvmf_tgt_listen_done(void *cb_arg
, int status
)
270 /* TODO: Config parsing should wait for this operation to finish. */
273 SPDK_ERRLOG("Failed to listen on transport address\n");
278 nvmf_parse_subsystem(struct spdk_conf_section
*sp
)
280 const char *nqn
, *mode
;
285 bool allow_any_listener
= true;
288 struct spdk_nvmf_subsystem
*subsystem
;
291 nqn
= spdk_conf_section_get_val(sp
, "NQN");
293 SPDK_ERRLOG("Subsystem missing NQN\n");
297 mode
= spdk_conf_section_get_val(sp
, "Mode");
298 lcore
= spdk_conf_section_get_intval(sp
, "Core");
299 num_ns
= spdk_conf_section_get_intval(sp
, "MaxNamespaces");
303 } else if (num_ns
> SPDK_NVMF_MAX_NAMESPACES
) {
304 num_ns
= SPDK_NVMF_MAX_NAMESPACES
;
307 /* Mode is no longer a valid parameter, but print out a nice
308 * message if it exists to inform users.
311 SPDK_NOTICELOG("Mode present in the [Subsystem] section of the config file.\n"
312 "Mode was removed as a valid parameter.\n");
313 if (strcasecmp(mode
, "Virtual") == 0) {
314 SPDK_NOTICELOG("Your mode value is 'Virtual' which is now the only possible mode.\n"
315 "Your configuration file will work as expected.\n");
317 SPDK_NOTICELOG("Please remove Mode from your configuration file.\n");
322 /* Core is no longer a valid parameter, but print out a nice
323 * message if it exists to inform users.
326 SPDK_NOTICELOG("Core present in the [Subsystem] section of the config file.\n"
327 "Core was removed as an option. Subsystems can now run on all available cores.\n");
328 SPDK_NOTICELOG("Please remove Core from your configuration file. Ignoring it and continuing.\n");
331 sn
= spdk_conf_section_get_val(sp
, "SN");
333 SPDK_ERRLOG("Subsystem %s: missing serial number\n", nqn
);
337 subsystem
= spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt
, nqn
, SPDK_NVMF_SUBTYPE_NVME
, num_ns
);
338 if (subsystem
== NULL
) {
342 if (spdk_nvmf_subsystem_set_sn(subsystem
, sn
)) {
343 SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", nqn
, sn
);
344 spdk_nvmf_subsystem_destroy(subsystem
);
349 mn
= spdk_conf_section_get_val(sp
, "MN");
352 "Subsystem %s: missing model number, will use default\n",
357 if (spdk_nvmf_subsystem_set_mn(subsystem
, mn
)) {
358 SPDK_ERRLOG("Subsystem %s: invalid model number '%s'\n", nqn
, mn
);
359 spdk_nvmf_subsystem_destroy(subsystem
);
366 struct spdk_nvmf_ns_opts ns_opts
;
367 struct spdk_bdev
*bdev
;
368 const char *bdev_name
;
369 const char *uuid_str
;
372 bdev_name
= spdk_conf_section_get_nmval(sp
, "Namespace", i
, 0);
377 bdev
= spdk_bdev_get_by_name(bdev_name
);
379 SPDK_ERRLOG("Could not find namespace bdev '%s'\n", bdev_name
);
380 spdk_nvmf_subsystem_destroy(subsystem
);
385 spdk_nvmf_ns_opts_get_defaults(&ns_opts
, sizeof(ns_opts
));
387 nsid_str
= spdk_conf_section_get_nmval(sp
, "Namespace", i
, 1);
390 unsigned long nsid_ul
= strtoul(nsid_str
, &end
, 0);
392 if (*end
!= '\0' || nsid_ul
== 0 || nsid_ul
>= UINT32_MAX
) {
393 SPDK_ERRLOG("Invalid NSID %s\n", nsid_str
);
394 spdk_nvmf_subsystem_destroy(subsystem
);
399 ns_opts
.nsid
= (uint32_t)nsid_ul
;
402 uuid_str
= spdk_conf_section_get_nmval(sp
, "Namespace", i
, 2);
404 if (spdk_uuid_parse(&ns_opts
.uuid
, uuid_str
)) {
405 SPDK_ERRLOG("Invalid UUID %s\n", uuid_str
);
406 spdk_nvmf_subsystem_destroy(subsystem
);
412 if (spdk_nvmf_subsystem_add_ns(subsystem
, bdev
, &ns_opts
, sizeof(ns_opts
), NULL
) == 0) {
413 SPDK_ERRLOG("Unable to add namespace\n");
414 spdk_nvmf_subsystem_destroy(subsystem
);
420 /* Parse Listen sections */
422 struct spdk_nvme_transport_id trid
= {{0}};
423 const char *transport
;
427 transport
= spdk_conf_section_get_nmval(sp
, "Listen", i
, 0);
432 if (spdk_nvme_transport_id_populate_trstring(&trid
, transport
)) {
433 SPDK_ERRLOG("Invalid listen address transport type '%s'\n", transport
);
437 if (spdk_nvme_transport_id_parse_trtype(&trid
.trtype
, transport
)) {
438 SPDK_ERRLOG("Invalid listen address transport type '%s'\n", transport
);
442 address
= spdk_conf_section_get_nmval(sp
, "Listen", i
, 1);
447 address_dup
= strdup(address
);
452 if (trid
.trtype
== SPDK_NVME_TRANSPORT_RDMA
||
453 trid
.trtype
== SPDK_NVME_TRANSPORT_TCP
) {
454 ret
= nvmf_tgt_parse_listen_ip_addr(address_dup
, &trid
);
455 } else if (trid
.trtype
== SPDK_NVME_TRANSPORT_FC
) {
456 ret
= nvmf_tgt_parse_listen_fc_addr(address_dup
, &trid
);
465 if (spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt
, &trid
)) {
466 SPDK_ERRLOG("Failed to listen on transport address\n");
469 spdk_nvmf_subsystem_add_listener(subsystem
, &trid
, nvmf_tgt_listen_done
, NULL
);
470 allow_any_listener
= false;
473 spdk_nvmf_subsystem_allow_any_listener(subsystem
, allow_any_listener
);
475 /* Parse Host sections */
477 const char *host
= spdk_conf_section_get_nval(sp
, "Host", i
);
483 spdk_nvmf_subsystem_add_host(subsystem
, host
);
486 allow_any_host
= spdk_conf_section_get_boolval(sp
, "AllowAnyHost", false);
487 spdk_nvmf_subsystem_set_allow_any_host(subsystem
, allow_any_host
);
490 return (subsystem
!= NULL
) ? 0 : -1;
494 nvmf_parse_subsystems(void)
497 struct spdk_conf_section
*sp
;
499 sp
= spdk_conf_first_section(NULL
);
501 if (spdk_conf_section_match_prefix(sp
, "Subsystem")) {
502 rc
= nvmf_parse_subsystem(sp
);
507 sp
= spdk_conf_next_section(sp
);
512 struct nvmf_parse_transport_ctx
{
513 struct spdk_conf_section
*sp
;
514 nvmf_parse_conf_done_fn cb_fn
;
517 static void nvmf_parse_transport(struct nvmf_parse_transport_ctx
*ctx
);
520 nvmf_tgt_add_transport_done(void *cb_arg
, int status
)
522 struct nvmf_parse_transport_ctx
*ctx
= cb_arg
;
526 SPDK_ERRLOG("Add transport to target failed (%d).\n", status
);
532 /* find next transport */
533 ctx
->sp
= spdk_conf_next_section(ctx
->sp
);
535 if (spdk_conf_section_match_prefix(ctx
->sp
, "Transport")) {
536 nvmf_parse_transport(ctx
);
539 ctx
->sp
= spdk_conf_next_section(ctx
->sp
);
542 /* done with transports, parse Subsystem sections */
543 rc
= nvmf_parse_subsystems();
550 nvmf_parse_transport(struct nvmf_parse_transport_ctx
*ctx
)
553 struct spdk_nvmf_transport_opts opts
= { 0 };
554 enum spdk_nvme_transport_type trtype
;
555 struct spdk_nvmf_transport
*transport
;
559 type
= spdk_conf_section_get_val(ctx
->sp
, "Type");
561 SPDK_ERRLOG("Transport missing Type\n");
567 spdk_nvme_transport_id_parse_trtype(&trtype
, type
);
569 if (spdk_nvmf_tgt_get_transport(g_spdk_nvmf_tgt
, type
)) {
570 SPDK_ERRLOG("Duplicate transport type '%s'\n", type
);
576 if (!spdk_nvmf_transport_opts_init(type
, &opts
)) {
582 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxQueueDepth");
584 opts
.max_queue_depth
= val
;
586 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxQueuesPerSession");
588 opts
.max_qpairs_per_ctrlr
= val
;
590 val
= spdk_conf_section_get_intval(ctx
->sp
, "InCapsuleDataSize");
592 opts
.in_capsule_data_size
= val
;
594 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxIOSize");
596 opts
.max_io_size
= val
;
598 val
= spdk_conf_section_get_intval(ctx
->sp
, "IOUnitSize");
600 opts
.io_unit_size
= val
;
602 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxAQDepth");
604 opts
.max_aq_depth
= val
;
606 val
= spdk_conf_section_get_intval(ctx
->sp
, "NumSharedBuffers");
608 opts
.num_shared_buffers
= val
;
610 val
= spdk_conf_section_get_intval(ctx
->sp
, "BufCacheSize");
612 opts
.buf_cache_size
= val
;
615 if (trtype
== SPDK_NVME_TRANSPORT_RDMA
) {
616 val
= spdk_conf_section_get_intval(ctx
->sp
, "MaxSRQDepth");
618 opts
.max_srq_depth
= val
;
620 bval
= spdk_conf_section_get_boolval(ctx
->sp
, "NoSRQ", false);
624 if (trtype
== SPDK_NVME_TRANSPORT_TCP
) {
625 bval
= spdk_conf_section_get_boolval(ctx
->sp
, "C2HSuccess", true);
626 opts
.c2h_success
= bval
;
628 val
= spdk_conf_section_get_intval(ctx
->sp
, "SockPriority");
630 opts
.sock_priority
= val
;
634 bval
= spdk_conf_section_get_boolval(ctx
->sp
, "DifInsertOrStrip", false);
635 opts
.dif_insert_or_strip
= bval
;
637 transport
= spdk_nvmf_transport_create(type
, &opts
);
639 spdk_nvmf_tgt_add_transport(g_spdk_nvmf_tgt
, transport
, nvmf_tgt_add_transport_done
, ctx
);
653 nvmf_parse_transports(nvmf_parse_conf_done_fn cb_fn
)
655 struct nvmf_parse_transport_ctx
*ctx
;
657 ctx
= calloc(1, sizeof(struct nvmf_parse_transport_ctx
));
659 SPDK_ERRLOG("Failed alloc of context memory for parse transports\n");
664 ctx
->sp
= spdk_conf_first_section(NULL
);
665 if (ctx
->sp
== NULL
) {
672 while (ctx
->sp
!= NULL
) {
673 if (spdk_conf_section_match_prefix(ctx
->sp
, "Transport")) {
674 nvmf_parse_transport(ctx
);
677 ctx
->sp
= spdk_conf_next_section(ctx
->sp
);
680 /* if we get here, there are no transports defined in conf file */
687 nvmf_parse_conf(nvmf_parse_conf_done_fn cb_fn
)
692 SPDK_ERRLOG("Callback function is NULL\n");
697 rc
= nvmf_parse_nvmf_tgt();
702 /* Transport sections */
703 rc
= nvmf_parse_transports(cb_fn
);