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