]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/event/subsystems/nvmf/conf.c
bump version to 15.2.11-pve1
[ceph.git] / ceph / src / spdk / lib / 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 spdk_add_nvmf_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 spdk_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 void
105 spdk_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
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;
113 }
114 }
115
116 static int
117 spdk_nvmf_parse_tgt_max_subsystems(void)
118 {
119 struct spdk_conf_section *sp;
120 int deprecated_values = 0;
121
122 sp = spdk_conf_find_section(NULL, "Nvmf");
123 if (sp != NULL) {
124 spdk_nvmf_read_config_file_tgt_max_subsystems(sp, &deprecated_values);
125 }
126
127 return deprecated_values;
128 }
129
130 static struct spdk_nvmf_tgt_conf *
131 spdk_nvmf_parse_tgt_conf(void)
132 {
133 struct spdk_nvmf_tgt_conf *conf;
134 struct spdk_conf_section *sp;
135
136 conf = calloc(1, sizeof(*conf));
137 if (!conf) {
138 SPDK_ERRLOG("calloc() failed for target conf\n");
139 return NULL;
140 }
141
142 conf->acceptor_poll_rate = ACCEPT_TIMEOUT_US;
143 conf->conn_sched = DEFAULT_CONN_SCHED;
144
145 sp = spdk_conf_find_section(NULL, "Nvmf");
146 if (sp != NULL) {
147 spdk_nvmf_read_config_file_tgt_conf(sp, conf);
148 }
149
150 return conf;
151 }
152
153 static int
154 spdk_nvmf_parse_nvmf_tgt(void)
155 {
156 int rc;
157 int using_deprecated_options;
158
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.");
168 }
169 }
170
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");
175 return -1;
176 }
177 }
178
179 g_spdk_nvmf_tgt = spdk_nvmf_tgt_create(g_spdk_nvmf_tgt_max_subsystems);
180
181 g_spdk_nvmf_tgt_max_subsystems = 0;
182
183 if (!g_spdk_nvmf_tgt) {
184 SPDK_ERRLOG("spdk_nvmf_tgt_create() failed\n");
185 return -1;
186 }
187
188 rc = spdk_add_nvmf_discovery_subsystem();
189 if (rc != 0) {
190 SPDK_ERRLOG("spdk_add_nvmf_discovery_subsystem failed\n");
191 return rc;
192 }
193
194 return 0;
195 }
196
197 static void
198 spdk_nvmf_tgt_listen_done(void *cb_arg, int status)
199 {
200 /* TODO: Config parsing should wait for this operation to finish. */
201
202 if (status) {
203 SPDK_ERRLOG("Failed to listen on transport address\n");
204 }
205 }
206
207 static int
208 spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp)
209 {
210 const char *nqn, *mode;
211 size_t i;
212 int ret;
213 int lcore;
214 bool allow_any_host;
215 const char *sn;
216 const char *mn;
217 struct spdk_nvmf_subsystem *subsystem;
218 int num_ns;
219
220 nqn = spdk_conf_section_get_val(sp, "NQN");
221 if (nqn == NULL) {
222 SPDK_ERRLOG("Subsystem missing NQN\n");
223 return -1;
224 }
225
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");
229
230 if (num_ns < 1) {
231 num_ns = 0;
232 } else if (num_ns > SPDK_NVMF_MAX_NAMESPACES) {
233 num_ns = SPDK_NVMF_MAX_NAMESPACES;
234 }
235
236 /* Mode is no longer a valid parameter, but print out a nice
237 * message if it exists to inform users.
238 */
239 if (mode) {
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");
245 } else {
246 SPDK_NOTICELOG("Please remove Mode from your configuration file.\n");
247 return -1;
248 }
249 }
250
251 /* Core is no longer a valid parameter, but print out a nice
252 * message if it exists to inform users.
253 */
254 if (lcore >= 0) {
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");
258 }
259
260 sn = spdk_conf_section_get_val(sp, "SN");
261 if (sn == NULL) {
262 SPDK_ERRLOG("Subsystem %s: missing serial number\n", nqn);
263 return -1;
264 }
265
266 subsystem = spdk_nvmf_subsystem_create(g_spdk_nvmf_tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, num_ns);
267 if (subsystem == NULL) {
268 goto done;
269 }
270
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);
274 subsystem = NULL;
275 goto done;
276 }
277
278 mn = spdk_conf_section_get_val(sp, "MN");
279 if (mn == NULL) {
280 SPDK_NOTICELOG(
281 "Subsystem %s: missing model number, will use default\n",
282 nqn);
283 }
284
285 if (mn != NULL) {
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);
289 subsystem = NULL;
290 goto done;
291 }
292 }
293
294 for (i = 0; ; i++) {
295 struct spdk_nvmf_ns_opts ns_opts;
296 struct spdk_bdev *bdev;
297 const char *bdev_name;
298 const char *uuid_str;
299 char *nsid_str;
300
301 bdev_name = spdk_conf_section_get_nmval(sp, "Namespace", i, 0);
302 if (!bdev_name) {
303 break;
304 }
305
306 bdev = spdk_bdev_get_by_name(bdev_name);
307 if (bdev == NULL) {
308 SPDK_ERRLOG("Could not find namespace bdev '%s'\n", bdev_name);
309 spdk_nvmf_subsystem_destroy(subsystem);
310 subsystem = NULL;
311 goto done;
312 }
313
314 spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
315
316 nsid_str = spdk_conf_section_get_nmval(sp, "Namespace", i, 1);
317 if (nsid_str) {
318 char *end;
319 unsigned long nsid_ul = strtoul(nsid_str, &end, 0);
320
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);
324 subsystem = NULL;
325 goto done;
326 }
327
328 ns_opts.nsid = (uint32_t)nsid_ul;
329 }
330
331 uuid_str = spdk_conf_section_get_nmval(sp, "Namespace", i, 2);
332 if (uuid_str) {
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);
336 subsystem = NULL;
337 goto done;
338 }
339 }
340
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);
344 subsystem = NULL;
345 goto done;
346 }
347
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));
350 }
351
352 /* Parse Listen sections */
353 for (i = 0; ; i++) {
354 struct spdk_nvme_transport_id trid = {0};
355 const char *transport;
356 const char *address;
357 char *address_dup;
358 char *host;
359 char *port;
360
361 transport = spdk_conf_section_get_nmval(sp, "Listen", i, 0);
362 if (!transport) {
363 break;
364 }
365
366 if (spdk_nvme_transport_id_parse_trtype(&trid.trtype, transport)) {
367 SPDK_ERRLOG("Invalid listen address transport type '%s'\n", transport);
368 continue;
369 }
370
371 address = spdk_conf_section_get_nmval(sp, "Listen", i, 1);
372 if (!address) {
373 break;
374 }
375
376 address_dup = strdup(address);
377 if (!address_dup) {
378 break;
379 }
380
381 ret = spdk_parse_ip_addr(address_dup, &host, &port);
382 if (ret < 0) {
383 SPDK_ERRLOG("Unable to parse listen address '%s'\n", address);
384 free(address_dup);
385 continue;
386 }
387
388 if (strchr(host, ':')) {
389 trid.adrfam = SPDK_NVMF_ADRFAM_IPV6;
390 } else {
391 trid.adrfam = SPDK_NVMF_ADRFAM_IPV4;
392 }
393
394 snprintf(trid.traddr, sizeof(trid.traddr), "%s", host);
395 if (port) {
396 snprintf(trid.trsvcid, sizeof(trid.trsvcid), "%s", port);
397 }
398 free(address_dup);
399
400 spdk_nvmf_tgt_listen(g_spdk_nvmf_tgt, &trid, spdk_nvmf_tgt_listen_done, NULL);
401
402 spdk_nvmf_subsystem_add_listener(subsystem, &trid);
403 }
404
405 /* Parse Host sections */
406 for (i = 0; ; i++) {
407 const char *host = spdk_conf_section_get_nval(sp, "Host", i);
408
409 if (!host) {
410 break;
411 }
412
413 spdk_nvmf_subsystem_add_host(subsystem, host);
414 }
415
416 allow_any_host = spdk_conf_section_get_boolval(sp, "AllowAnyHost", false);
417 spdk_nvmf_subsystem_set_allow_any_host(subsystem, allow_any_host);
418
419 done:
420 return (subsystem != NULL);
421 }
422
423 static int
424 spdk_nvmf_parse_subsystems(void)
425 {
426 int rc = 0;
427 struct spdk_conf_section *sp;
428
429 sp = spdk_conf_first_section(NULL);
430 while (sp != NULL) {
431 if (spdk_conf_section_match_prefix(sp, "Subsystem")) {
432 rc = spdk_nvmf_parse_subsystem(sp);
433 if (rc < 0) {
434 return -1;
435 }
436 }
437 sp = spdk_conf_next_section(sp);
438 }
439 return 0;
440 }
441
442 struct spdk_nvmf_parse_transport_ctx {
443 struct spdk_conf_section *sp;
444 spdk_nvmf_parse_conf_done_fn cb_fn;
445 };
446
447 static void spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx *ctx);
448
449 static void
450 spdk_nvmf_tgt_add_transport_done(void *cb_arg, int status)
451 {
452 struct spdk_nvmf_parse_transport_ctx *ctx = cb_arg;
453 int rc;
454
455 if (status < 0) {
456 SPDK_ERRLOG("Add transport to target failed (%d).\n", status);
457 ctx->cb_fn(status);
458 free(ctx);
459 return;
460 }
461
462 /* find next transport */
463 ctx->sp = spdk_conf_next_section(ctx->sp);
464 while (ctx->sp) {
465 if (spdk_conf_section_match_prefix(ctx->sp, "Transport")) {
466 spdk_nvmf_parse_transport(ctx);
467 return;
468 }
469 ctx->sp = spdk_conf_next_section(ctx->sp);
470 }
471
472 /* done with transports, parse Subsystem sections */
473 rc = spdk_nvmf_parse_subsystems();
474
475 ctx->cb_fn(rc);
476 free(ctx);
477 }
478
479 static void
480 spdk_nvmf_parse_transport(struct spdk_nvmf_parse_transport_ctx *ctx)
481 {
482 const char *type;
483 struct spdk_nvmf_transport_opts opts = { 0 };
484 enum spdk_nvme_transport_type trtype;
485 struct spdk_nvmf_transport *transport;
486 int val;
487
488 type = spdk_conf_section_get_val(ctx->sp, "Type");
489 if (type == NULL) {
490 SPDK_ERRLOG("Transport missing Type\n");
491 ctx->cb_fn(-1);
492 free(ctx);
493 return;
494 }
495
496 if (spdk_nvme_transport_id_parse_trtype(&trtype, type)) {
497 SPDK_ERRLOG("Invalid transport type '%s'\n", type);
498 ctx->cb_fn(-1);
499 free(ctx);
500 return;
501 }
502
503 if (spdk_nvmf_tgt_get_transport(g_spdk_nvmf_tgt, trtype)) {
504 SPDK_ERRLOG("Duplicate transport type '%s'\n", type);
505 ctx->cb_fn(-1);
506 free(ctx);
507 return;
508 }
509
510 if (!spdk_nvmf_transport_opts_init(trtype, &opts)) {
511 ctx->cb_fn(-1);
512 free(ctx);
513 return;
514 }
515
516 val = spdk_conf_section_get_intval(ctx->sp, "MaxQueueDepth");
517 if (val >= 0) {
518 opts.max_queue_depth = val;
519 }
520 val = spdk_conf_section_get_intval(ctx->sp, "MaxQueuesPerSession");
521 if (val >= 0) {
522 opts.max_qpairs_per_ctrlr = val;
523 }
524 val = spdk_conf_section_get_intval(ctx->sp, "InCapsuleDataSize");
525 if (val >= 0) {
526 opts.in_capsule_data_size = val;
527 }
528 val = spdk_conf_section_get_intval(ctx->sp, "MaxIOSize");
529 if (val >= 0) {
530 opts.max_io_size = val;
531 }
532 val = spdk_conf_section_get_intval(ctx->sp, "IOUnitSize");
533 if (val >= 0) {
534 opts.io_unit_size = val;
535 }
536 val = spdk_conf_section_get_intval(ctx->sp, "MaxAQDepth");
537 if (val >= 0) {
538 opts.max_aq_depth = val;
539 }
540 val = spdk_conf_section_get_intval(ctx->sp, "NumSharedBuffers");
541 if (val >= 0) {
542 opts.num_shared_buffers = val;
543 }
544 val = spdk_conf_section_get_intval(ctx->sp, "BufCacheSize");
545 if (val >= 0) {
546 opts.buf_cache_size = val;
547 }
548
549 val = spdk_conf_section_get_intval(ctx->sp, "MaxSRQDepth");
550 if (val >= 0) {
551 if (trtype == SPDK_NVME_TRANSPORT_RDMA) {
552 opts.max_srq_depth = val;
553 } else {
554 SPDK_ERRLOG("MaxSRQDepth is relevant only for RDMA transport '%s'\n", type);
555 ctx->cb_fn(-1);
556 free(ctx);
557 return;
558 }
559 }
560
561 transport = spdk_nvmf_transport_create(trtype, &opts);
562 if (transport) {
563 spdk_nvmf_tgt_add_transport(g_spdk_nvmf_tgt, transport, spdk_nvmf_tgt_add_transport_done, ctx);
564 } else {
565 ctx->cb_fn(-1);
566 free(ctx);
567 return;
568 }
569 }
570
571 static int
572 spdk_nvmf_parse_transports(spdk_nvmf_parse_conf_done_fn cb_fn)
573 {
574 struct spdk_nvmf_parse_transport_ctx *ctx;
575
576 ctx = calloc(1, sizeof(struct spdk_nvmf_parse_transport_ctx));
577 if (!ctx) {
578 SPDK_ERRLOG("Failed alloc of context memory for parse transports\n");
579 return -ENOMEM;
580 }
581
582 ctx->cb_fn = cb_fn;
583 ctx->sp = spdk_conf_first_section(NULL);
584 if (ctx->sp == NULL) {
585 free(ctx);
586 cb_fn(0);
587
588 return 0;
589 }
590
591 while (ctx->sp != NULL) {
592 if (spdk_conf_section_match_prefix(ctx->sp, "Transport")) {
593 spdk_nvmf_parse_transport(ctx);
594 return 0;
595 }
596 ctx->sp = spdk_conf_next_section(ctx->sp);
597 }
598
599 /* if we get here, there are no transports defined in conf file */
600 free(ctx);
601 cb_fn(0);
602 return 0;
603 }
604
605 int
606 spdk_nvmf_parse_conf(spdk_nvmf_parse_conf_done_fn cb_fn)
607 {
608 int rc;
609
610 if (cb_fn == NULL) {
611 SPDK_ERRLOG("Callback function is NULL\n");
612 return -1;
613 }
614
615 /* NVMf section */
616 rc = spdk_nvmf_parse_nvmf_tgt();
617 if (rc < 0) {
618 return rc;
619 }
620
621 /* Transport sections */
622 rc = spdk_nvmf_parse_transports(cb_fn);
623 if (rc < 0) {
624 return rc;
625 }
626
627 return 0;
628 }