]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/module/event/subsystems/nvmf/conf.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / module / event / subsystems / nvmf / conf.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation. All rights reserved.
5 * Copyright (c) 2018 Mellanox Technologies LTD. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
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
16 * distribution.
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.
20 *
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.
32 */
33
34 #include "event_nvmf.h"
35
36 #include "spdk/conf.h"
37 #include "spdk/log.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"
43
44 #define SPDK_NVMF_MAX_NAMESPACES (1 << 14)
45
46 struct spdk_nvmf_tgt_conf *g_spdk_nvmf_tgt_conf = NULL;
47 uint32_t g_spdk_nvmf_tgt_max_subsystems = 0;
48
49 static int
50 nvmf_add_discovery_subsystem(void)
51 {
52 struct spdk_nvmf_subsystem *subsystem;
53
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");
58 return -1;
59 }
60
61 spdk_nvmf_subsystem_set_allow_any_host(subsystem, true);
62
63 return 0;
64 }
65
66 static void
67 nvmf_read_config_file_tgt_max_subsystems(struct spdk_conf_section *sp,
68 int *deprecated_values)
69 {
70 int tgt_max_subsystems;
71 int deprecated;
72
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;
76 }
77
78 deprecated = spdk_conf_section_get_intval(sp, "MaxQueueDepth");
79 if (deprecated >= 0) {
80 *deprecated_values = -1;
81 }
82
83 deprecated = spdk_conf_section_get_intval(sp, "MaxQueuesPerSession");
84 if (deprecated >= 0) {
85 *deprecated_values = -1;
86 }
87
88 deprecated = spdk_conf_section_get_intval(sp, "InCapsuleDataSize");
89 if (deprecated >= 0) {
90 *deprecated_values = -1;
91 }
92
93 deprecated = spdk_conf_section_get_intval(sp, "MaxIOSize");
94 if (deprecated >= 0) {
95 *deprecated_values = -1;
96 }
97
98 deprecated = spdk_conf_section_get_intval(sp, "IOUnitSize");
99 if (deprecated >= 0) {
100 *deprecated_values = -1;
101 }
102 }
103
104 static int
105 nvmf_read_config_file_tgt_conf(struct spdk_conf_section *sp,
106 struct spdk_nvmf_tgt_conf *conf)
107 {
108 int acceptor_poll_rate;
109 const char *conn_scheduler;
110 int rc = 0;
111
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;
115 }
116
117 conn_scheduler = spdk_conf_section_get_val(sp, "ConnectionScheduler");
118
119 if (conn_scheduler) {
120 SPDK_NOTICELOG("The ConnectionScheduler option is no longer valid. Ignoring it.\n");
121 }
122
123 conf->admin_passthru.identify_ctrlr = spdk_conf_section_get_boolval(sp,
124 "AdminCmdPassthruIdentifyCtrlr", false);
125
126 return rc;
127 }
128
129 static int
130 nvmf_parse_tgt_max_subsystems(void)
131 {
132 struct spdk_conf_section *sp;
133 int deprecated_values = 0;
134
135 sp = spdk_conf_find_section(NULL, "Nvmf");
136 if (sp != NULL) {
137 nvmf_read_config_file_tgt_max_subsystems(sp, &deprecated_values);
138 }
139
140 return deprecated_values;
141 }
142
143 static struct spdk_nvmf_tgt_conf *
144 nvmf_parse_tgt_conf(void)
145 {
146 struct spdk_nvmf_tgt_conf *conf;
147 struct spdk_conf_section *sp;
148 int rc;
149
150 conf = calloc(1, sizeof(*conf));
151 if (!conf) {
152 SPDK_ERRLOG("calloc() failed for target conf\n");
153 return NULL;
154 }
155
156 conf->acceptor_poll_rate = ACCEPT_TIMEOUT_US;
157 conf->admin_passthru.identify_ctrlr = false;
158
159 sp = spdk_conf_find_section(NULL, "Nvmf");
160 if (sp != NULL) {
161 rc = nvmf_read_config_file_tgt_conf(sp, conf);
162 if (rc) {
163 free(conf);
164 return NULL;
165 }
166 }
167
168 return conf;
169 }
170
171 static int
172 nvmf_parse_nvmf_tgt(void)
173 {
174 int rc;
175 int using_deprecated_options;
176 struct spdk_nvmf_target_opts opts = {
177 .name = "nvmf_tgt",
178 .max_subsystems = 0
179 };
180
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.");
190 }
191 }
192
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");
197 return -1;
198 }
199 }
200
201 opts.max_subsystems = g_spdk_nvmf_tgt_max_subsystems;
202 g_spdk_nvmf_tgt = spdk_nvmf_tgt_create(&opts);
203
204 g_spdk_nvmf_tgt_max_subsystems = 0;
205
206 if (!g_spdk_nvmf_tgt) {
207 SPDK_ERRLOG("spdk_nvmf_tgt_create() failed\n");
208 return -1;
209 }
210
211 rc = nvmf_add_discovery_subsystem();
212 if (rc != 0) {
213 SPDK_ERRLOG("nvmf_add_discovery_subsystem failed\n");
214 return rc;
215 }
216
217 return 0;
218 }
219
220 static int
221 nvmf_tgt_parse_listen_ip_addr(char *address,
222 struct spdk_nvme_transport_id *trid)
223 {
224 char *host;
225 char *port;
226
227 if (spdk_parse_ip_addr(address, &host, &port) < 0) {
228 SPDK_ERRLOG("Unable to parse listen address '%s'\n", address);
229 return -1;
230 }
231
232 if (strchr(host, ':')) {
233 trid->adrfam = SPDK_NVMF_ADRFAM_IPV6;
234 } else {
235 trid->adrfam = SPDK_NVMF_ADRFAM_IPV4;
236 }
237
238 snprintf(trid->traddr, sizeof(trid->traddr), "%s", host);
239 if (port) {
240 snprintf(trid->trsvcid, sizeof(trid->trsvcid), "%s", port);
241 }
242
243 return 0;
244 }
245
246 static int
247 nvmf_tgt_parse_listen_fc_addr(const char *address,
248 struct spdk_nvme_transport_id *trid)
249 {
250 /* transport address format and requirements,
251 * "nn-0xWWNN:pn-0xWWPN" - size equals 43 bytes and is required to
252 * contain 'nn' and 'pn'.
253 */
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);
257 return -1;
258 }
259
260 trid->adrfam = SPDK_NVMF_ADRFAM_FC;
261 snprintf(trid->trsvcid, sizeof(trid->trsvcid), "none");
262 snprintf(trid->traddr, sizeof(trid->traddr), "%s", address);
263
264 return 0;
265 }
266
267 static void
268 nvmf_tgt_listen_done(void *cb_arg, int status)
269 {
270 /* TODO: Config parsing should wait for this operation to finish. */
271
272 if (status) {
273 SPDK_ERRLOG("Failed to listen on transport address\n");
274 }
275 }
276
277 static int
278 nvmf_parse_subsystem(struct spdk_conf_section *sp)
279 {
280 const char *nqn, *mode;
281 size_t i;
282 int ret = -1;
283 int lcore;
284 bool allow_any_host;
285 bool allow_any_listener = true;
286 const char *sn;
287 const char *mn;
288 struct spdk_nvmf_subsystem *subsystem;
289 int num_ns;
290
291 nqn = spdk_conf_section_get_val(sp, "NQN");
292 if (nqn == NULL) {
293 SPDK_ERRLOG("Subsystem missing NQN\n");
294 return -1;
295 }
296
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");
300
301 if (num_ns < 1) {
302 num_ns = 0;
303 } else if (num_ns > SPDK_NVMF_MAX_NAMESPACES) {
304 num_ns = SPDK_NVMF_MAX_NAMESPACES;
305 }
306
307 /* Mode is no longer a valid parameter, but print out a nice
308 * message if it exists to inform users.
309 */
310 if (mode) {
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");
316 } else {
317 SPDK_NOTICELOG("Please remove Mode from your configuration file.\n");
318 return -1;
319 }
320 }
321
322 /* Core is no longer a valid parameter, but print out a nice
323 * message if it exists to inform users.
324 */
325 if (lcore >= 0) {
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");
329 }
330
331 sn = spdk_conf_section_get_val(sp, "SN");
332 if (sn == NULL) {
333 SPDK_ERRLOG("Subsystem %s: missing serial number\n", nqn);
334 return -1;
335 }
336
337 subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, num_ns);
338 if (subsystem == NULL) {
339 goto done;
340 }
341
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);
345 subsystem = NULL;
346 goto done;
347 }
348
349 mn = spdk_conf_section_get_val(sp, "MN");
350 if (mn == NULL) {
351 SPDK_NOTICELOG(
352 "Subsystem %s: missing model number, will use default\n",
353 nqn);
354 }
355
356 if (mn != NULL) {
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);
360 subsystem = NULL;
361 goto done;
362 }
363 }
364
365 for (i = 0; ; i++) {
366 struct spdk_nvmf_ns_opts ns_opts;
367 struct spdk_bdev *bdev;
368 const char *bdev_name;
369 const char *uuid_str;
370 char *nsid_str;
371
372 bdev_name = spdk_conf_section_get_nmval(sp, "Namespace", i, 0);
373 if (!bdev_name) {
374 break;
375 }
376
377 bdev = spdk_bdev_get_by_name(bdev_name);
378 if (bdev == NULL) {
379 SPDK_ERRLOG("Could not find namespace bdev '%s'\n", bdev_name);
380 spdk_nvmf_subsystem_destroy(subsystem);
381 subsystem = NULL;
382 goto done;
383 }
384
385 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
386
387 nsid_str = spdk_conf_section_get_nmval(sp, "Namespace", i, 1);
388 if (nsid_str) {
389 char *end;
390 unsigned long nsid_ul = strtoul(nsid_str, &end, 0);
391
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);
395 subsystem = NULL;
396 goto done;
397 }
398
399 ns_opts.nsid = (uint32_t)nsid_ul;
400 }
401
402 uuid_str = spdk_conf_section_get_nmval(sp, "Namespace", i, 2);
403 if (uuid_str) {
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);
407 subsystem = NULL;
408 goto done;
409 }
410 }
411
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);
415 subsystem = NULL;
416 goto done;
417 }
418 }
419
420 /* Parse Listen sections */
421 for (i = 0; ; i++) {
422 struct spdk_nvme_transport_id trid = {{0}};
423 const char *transport;
424 const char *address;
425 char *address_dup;
426
427 transport = spdk_conf_section_get_nmval(sp, "Listen", i, 0);
428 if (!transport) {
429 break;
430 }
431
432 if (spdk_nvme_transport_id_populate_trstring(&trid, transport)) {
433 SPDK_ERRLOG("Invalid listen address transport type '%s'\n", transport);
434 continue;
435 }
436
437 if (spdk_nvme_transport_id_parse_trtype(&trid.trtype, transport)) {
438 SPDK_ERRLOG("Invalid listen address transport type '%s'\n", transport);
439 continue;
440 }
441
442 address = spdk_conf_section_get_nmval(sp, "Listen", i, 1);
443 if (!address) {
444 break;
445 }
446
447 address_dup = strdup(address);
448 if (!address_dup) {
449 break;
450 }
451
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);
457 }
458
459 free(address_dup);
460
461 if (ret) {
462 continue;
463 }
464
465 if (spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid)) {
466 SPDK_ERRLOG("Failed to listen on transport address\n");
467 }
468
469 spdk_nvmf_subsystem_add_listener(subsystem, &trid, nvmf_tgt_listen_done, NULL);
470 allow_any_listener = false;
471 }
472
473 spdk_nvmf_subsystem_allow_any_listener(subsystem, allow_any_listener);
474
475 /* Parse Host sections */
476 for (i = 0; ; i++) {
477 const char *host = spdk_conf_section_get_nval(sp, "Host", i);
478
479 if (!host) {
480 break;
481 }
482
483 spdk_nvmf_subsystem_add_host(subsystem, host);
484 }
485
486 allow_any_host = spdk_conf_section_get_boolval(sp, "AllowAnyHost", false);
487 spdk_nvmf_subsystem_set_allow_any_host(subsystem, allow_any_host);
488
489 done:
490 return (subsystem != NULL) ? 0 : -1;
491 }
492
493 static int
494 nvmf_parse_subsystems(void)
495 {
496 int rc = 0;
497 struct spdk_conf_section *sp;
498
499 sp = spdk_conf_first_section(NULL);
500 while (sp != NULL) {
501 if (spdk_conf_section_match_prefix(sp, "Subsystem")) {
502 rc = nvmf_parse_subsystem(sp);
503 if (rc < 0) {
504 return -1;
505 }
506 }
507 sp = spdk_conf_next_section(sp);
508 }
509 return 0;
510 }
511
512 struct nvmf_parse_transport_ctx {
513 struct spdk_conf_section *sp;
514 nvmf_parse_conf_done_fn cb_fn;
515 };
516
517 static void nvmf_parse_transport(struct nvmf_parse_transport_ctx *ctx);
518
519 static void
520 nvmf_tgt_add_transport_done(void *cb_arg, int status)
521 {
522 struct nvmf_parse_transport_ctx *ctx = cb_arg;
523 int rc;
524
525 if (status < 0) {
526 SPDK_ERRLOG("Add transport to target failed (%d).\n", status);
527 ctx->cb_fn(status);
528 free(ctx);
529 return;
530 }
531
532 /* find next transport */
533 ctx->sp = spdk_conf_next_section(ctx->sp);
534 while (ctx->sp) {
535 if (spdk_conf_section_match_prefix(ctx->sp, "Transport")) {
536 nvmf_parse_transport(ctx);
537 return;
538 }
539 ctx->sp = spdk_conf_next_section(ctx->sp);
540 }
541
542 /* done with transports, parse Subsystem sections */
543 rc = nvmf_parse_subsystems();
544
545 ctx->cb_fn(rc);
546 free(ctx);
547 }
548
549 static void
550 nvmf_parse_transport(struct nvmf_parse_transport_ctx *ctx)
551 {
552 const char *type;
553 struct spdk_nvmf_transport_opts opts = { 0 };
554 enum spdk_nvme_transport_type trtype;
555 struct spdk_nvmf_transport *transport;
556 bool bval;
557 int val;
558
559 type = spdk_conf_section_get_val(ctx->sp, "Type");
560 if (type == NULL) {
561 SPDK_ERRLOG("Transport missing Type\n");
562 ctx->cb_fn(-1);
563 free(ctx);
564 return;
565 }
566
567 spdk_nvme_transport_id_parse_trtype(&trtype, type);
568
569 if (spdk_nvmf_tgt_get_transport(g_spdk_nvmf_tgt, type)) {
570 SPDK_ERRLOG("Duplicate transport type '%s'\n", type);
571 ctx->cb_fn(-1);
572 free(ctx);
573 return;
574 }
575
576 if (!spdk_nvmf_transport_opts_init(type, &opts)) {
577 ctx->cb_fn(-1);
578 free(ctx);
579 return;
580 }
581
582 val = spdk_conf_section_get_intval(ctx->sp, "MaxQueueDepth");
583 if (val >= 0) {
584 opts.max_queue_depth = val;
585 }
586 val = spdk_conf_section_get_intval(ctx->sp, "MaxQueuesPerSession");
587 if (val >= 0) {
588 opts.max_qpairs_per_ctrlr = val;
589 }
590 val = spdk_conf_section_get_intval(ctx->sp, "InCapsuleDataSize");
591 if (val >= 0) {
592 opts.in_capsule_data_size = val;
593 }
594 val = spdk_conf_section_get_intval(ctx->sp, "MaxIOSize");
595 if (val >= 0) {
596 opts.max_io_size = val;
597 }
598 val = spdk_conf_section_get_intval(ctx->sp, "IOUnitSize");
599 if (val >= 0) {
600 opts.io_unit_size = val;
601 }
602 val = spdk_conf_section_get_intval(ctx->sp, "MaxAQDepth");
603 if (val >= 0) {
604 opts.max_aq_depth = val;
605 }
606 val = spdk_conf_section_get_intval(ctx->sp, "NumSharedBuffers");
607 if (val >= 0) {
608 opts.num_shared_buffers = val;
609 }
610 val = spdk_conf_section_get_intval(ctx->sp, "BufCacheSize");
611 if (val >= 0) {
612 opts.buf_cache_size = val;
613 }
614
615 if (trtype == SPDK_NVME_TRANSPORT_RDMA) {
616 val = spdk_conf_section_get_intval(ctx->sp, "MaxSRQDepth");
617 if (val >= 0) {
618 opts.max_srq_depth = val;
619 }
620 bval = spdk_conf_section_get_boolval(ctx->sp, "NoSRQ", false);
621 opts.no_srq = bval;
622 }
623
624 if (trtype == SPDK_NVME_TRANSPORT_TCP) {
625 bval = spdk_conf_section_get_boolval(ctx->sp, "C2HSuccess", true);
626 opts.c2h_success = bval;
627
628 val = spdk_conf_section_get_intval(ctx->sp, "SockPriority");
629 if (val >= 0) {
630 opts.sock_priority = val;
631 }
632 }
633
634 bval = spdk_conf_section_get_boolval(ctx->sp, "DifInsertOrStrip", false);
635 opts.dif_insert_or_strip = bval;
636
637 transport = spdk_nvmf_transport_create(type, &opts);
638 if (transport) {
639 spdk_nvmf_tgt_add_transport(g_spdk_nvmf_tgt, transport, nvmf_tgt_add_transport_done, ctx);
640 } else {
641 goto error_out;
642 }
643
644 return;
645
646 error_out:
647 ctx->cb_fn(-1);
648 free(ctx);
649 return;
650 }
651
652 static int
653 nvmf_parse_transports(nvmf_parse_conf_done_fn cb_fn)
654 {
655 struct nvmf_parse_transport_ctx *ctx;
656
657 ctx = calloc(1, sizeof(struct nvmf_parse_transport_ctx));
658 if (!ctx) {
659 SPDK_ERRLOG("Failed alloc of context memory for parse transports\n");
660 return -ENOMEM;
661 }
662
663 ctx->cb_fn = cb_fn;
664 ctx->sp = spdk_conf_first_section(NULL);
665 if (ctx->sp == NULL) {
666 free(ctx);
667 cb_fn(0);
668
669 return 0;
670 }
671
672 while (ctx->sp != NULL) {
673 if (spdk_conf_section_match_prefix(ctx->sp, "Transport")) {
674 nvmf_parse_transport(ctx);
675 return 0;
676 }
677 ctx->sp = spdk_conf_next_section(ctx->sp);
678 }
679
680 /* if we get here, there are no transports defined in conf file */
681 free(ctx);
682 cb_fn(0);
683 return 0;
684 }
685
686 int
687 nvmf_parse_conf(nvmf_parse_conf_done_fn cb_fn)
688 {
689 int rc;
690
691 if (cb_fn == NULL) {
692 SPDK_ERRLOG("Callback function is NULL\n");
693 return -1;
694 }
695
696 /* NVMf section */
697 rc = nvmf_parse_nvmf_tgt();
698 if (rc < 0) {
699 return rc;
700 }
701
702 /* Transport sections */
703 rc = nvmf_parse_transports(cb_fn);
704 if (rc < 0) {
705 return rc;
706 }
707
708 return 0;
709 }