]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/iscsi/portal_grp.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / spdk / lib / iscsi / portal_grp.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5 * Copyright (c) Intel Corporation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * * Neither the name of Intel Corporation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <assert.h>
36 #include <inttypes.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <poll.h>
44 #include <pthread.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <signal.h>
48
49 #include <sys/types.h>
50
51 #include "spdk/conf.h"
52 #include "spdk/net.h"
53
54 #include "spdk_internal/log.h"
55
56 #include "iscsi/iscsi.h"
57 #include "iscsi/tgt_node.h"
58 #include "iscsi/conn.h"
59 #include "iscsi/portal_grp.h"
60
61 #define PORTNUMSTRLEN 32
62
63 static int
64 spdk_iscsi_portal_grp_open(struct spdk_iscsi_portal_grp *pg);
65
66 /* Assumes caller allocated host and port strings on the heap */
67 struct spdk_iscsi_portal *
68 spdk_iscsi_portal_create(const char *host, const char *port, uint64_t cpumask)
69 {
70 struct spdk_iscsi_portal *p = NULL;
71
72 assert(host != NULL);
73 assert(port != NULL);
74
75 p = malloc(sizeof(*p));
76 if (!p) {
77 SPDK_ERRLOG("portal malloc error (%s, %s)\n", host, port);
78 return NULL;
79 }
80 p->host = strdup(host);
81 p->port = strdup(port);
82 p->cpumask = cpumask;
83 p->sock = -1;
84 p->group = NULL; /* set at a later time by caller */
85
86 return p;
87 }
88
89 void
90 spdk_iscsi_portal_destroy(struct spdk_iscsi_portal *p)
91 {
92 assert(p != NULL);
93
94 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_iscsi_portal_destroy\n");
95 free(p->host);
96 free(p->port);
97 free(p);
98 }
99
100 static int
101 spdk_iscsi_portal_create_from_configline(const char *portalstring,
102 struct spdk_iscsi_portal **ip,
103 int dry_run)
104 {
105 char *host = NULL, *port = NULL;
106 const char *cpumask_str;
107 uint64_t cpumask = 0;
108
109 int n, len, rc = -1;
110 const char *p, *q;
111
112 if (portalstring == NULL) {
113 SPDK_ERRLOG("portal error\n");
114 goto error_out;
115 }
116
117 if (portalstring[0] == '[') {
118 /* IPv6 */
119 p = strchr(portalstring + 1, ']');
120 if (p == NULL) {
121 SPDK_ERRLOG("portal error\n");
122 goto error_out;
123 }
124 p++;
125 n = p - portalstring;
126 if (!dry_run) {
127 host = malloc(n + 1);
128 if (!host) {
129 perror("host");
130 goto error_out;
131 }
132 memcpy(host, portalstring, n);
133 host[n] = '\0';
134 }
135 if (p[0] == '\0') {
136 if (!dry_run) {
137 port = malloc(PORTNUMSTRLEN);
138 if (!port) {
139 perror("port");
140 goto error_out;
141 }
142 snprintf(port, PORTNUMSTRLEN, "%d", DEFAULT_PORT);
143 }
144 } else {
145 if (p[0] != ':') {
146 SPDK_ERRLOG("portal error\n");
147 goto error_out;
148 }
149 if (!dry_run) {
150 q = strchr(portalstring, '@');
151 if (q == NULL) {
152 q = portalstring + strlen(portalstring);
153 }
154 len = q - p - 1;
155
156 port = malloc(len + 1);
157 if (!port) {
158 perror("port");
159 goto error_out;
160 }
161 memset(port, 0, len + 1);
162 memcpy(port, p + 1, len);
163 }
164 }
165 } else {
166 /* IPv4 */
167 p = strchr(portalstring, ':');
168 if (p == NULL) {
169 p = portalstring + strlen(portalstring);
170 }
171 n = p - portalstring;
172 if (!dry_run) {
173 host = malloc(n + 1);
174 if (!host) {
175 perror("host");
176 goto error_out;
177 }
178 memcpy(host, portalstring, n);
179 host[n] = '\0';
180 }
181 if (p[0] == '\0') {
182 if (!dry_run) {
183 port = malloc(PORTNUMSTRLEN);
184 if (!port) {
185 perror("port");
186 goto error_out;
187 }
188 snprintf(port, PORTNUMSTRLEN, "%d", DEFAULT_PORT);
189 }
190 } else {
191 if (p[0] != ':') {
192 SPDK_ERRLOG("portal error\n");
193 goto error_out;
194 }
195 if (!dry_run) {
196 q = strchr(portalstring, '@');
197 if (q == NULL) {
198 q = portalstring + strlen(portalstring);
199 }
200
201 if (q == p) {
202 SPDK_ERRLOG("no port specified\n");
203 goto error_out;
204 }
205
206 len = q - p - 1;
207 port = malloc(len + 1);
208 if (!port) {
209 perror("port");
210 goto error_out;
211 }
212 memset(port, 0, len + 1);
213 memcpy(port, p + 1, len);
214 }
215
216 }
217 }
218
219 p = strchr(portalstring, '@');
220 if (p != NULL) {
221 cpumask_str = p + 1;
222 if (spdk_app_parse_core_mask(cpumask_str, &cpumask)) {
223 SPDK_ERRLOG("invalid portal cpumask %s\n", cpumask_str);
224 goto error_out;
225 }
226 if ((cpumask & spdk_app_get_core_mask()) != cpumask) {
227 SPDK_ERRLOG("portal cpumask %s not a subset of "
228 "reactor mask %jx\n", cpumask_str,
229 spdk_app_get_core_mask());
230 goto error_out;
231 }
232 } else {
233 cpumask = spdk_app_get_core_mask();
234 }
235
236 if (!dry_run) {
237 *ip = spdk_iscsi_portal_create(host, port, cpumask);
238 if (!*ip) {
239 goto error_out;
240 }
241 }
242
243 rc = 0;
244 error_out:
245 free(host);
246 free(port);
247
248 return rc;
249 }
250
251 struct spdk_iscsi_portal_grp *
252 spdk_iscsi_portal_grp_create(int tag)
253 {
254 struct spdk_iscsi_portal_grp *pg = malloc(sizeof(*pg));
255
256 if (!pg) {
257 SPDK_ERRLOG("portal group malloc error (%d)\n", tag);
258 return NULL;
259 }
260
261 /* Make sure there are no duplicate portal group tags */
262 if (spdk_iscsi_portal_grp_find_by_tag(tag)) {
263 SPDK_ERRLOG("portal group creation failed. duplicate portal group tag (%d)\n", tag);
264 free(pg);
265 return NULL;
266 }
267
268 pg->state = GROUP_INIT;
269 pg->ref = 0;
270 pg->tag = tag;
271
272 TAILQ_INIT(&pg->head);
273
274 return pg;
275 }
276
277 void
278 spdk_iscsi_portal_grp_destroy(struct spdk_iscsi_portal_grp *pg)
279 {
280 struct spdk_iscsi_portal *p;
281
282 assert(pg != NULL);
283
284 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_iscsi_portal_grp_destroy\n");
285 while (!TAILQ_EMPTY(&pg->head)) {
286 p = TAILQ_FIRST(&pg->head);
287 TAILQ_REMOVE(&pg->head, p, tailq);
288 spdk_iscsi_portal_destroy(p);
289 }
290 free(pg);
291 }
292
293 static void
294 spdk_iscsi_portal_grp_register(struct spdk_iscsi_portal_grp *pg)
295 {
296 assert(pg != NULL);
297 assert(!TAILQ_EMPTY(&pg->head));
298
299 pthread_mutex_lock(&g_spdk_iscsi.mutex);
300 pg->state = GROUP_READY;
301 TAILQ_INSERT_TAIL(&g_spdk_iscsi.pg_head, pg, tailq);
302 pthread_mutex_unlock(&g_spdk_iscsi.mutex);
303 }
304
305 /**
306 * If all portals are valid, this function will take their ownership.
307 */
308 int
309 spdk_iscsi_portal_grp_create_from_portal_list(int tag,
310 struct spdk_iscsi_portal **portal_list,
311 int num_portals)
312 {
313 int i = 0, rc = 0, port;
314 struct spdk_iscsi_portal_grp *pg;
315
316 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "add portal group (from portal list) %d\n", tag);
317
318 if (num_portals > MAX_PORTAL) {
319 SPDK_ERRLOG("%d > MAX_PORTAL\n", num_portals);
320 return -1;
321 }
322
323 pg = spdk_iscsi_portal_grp_create(tag);
324 if (!pg) {
325 SPDK_ERRLOG("portal group creation error (%d)\n", tag);
326 return -1;
327 }
328
329 for (i = 0; i < num_portals; i++) {
330 struct spdk_iscsi_portal *p = portal_list[i];
331
332 SPDK_TRACELOG(SPDK_TRACE_DEBUG,
333 "RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
334 i, p->host, p->port, tag);
335
336 port = (int)strtol(p->port, NULL, 0);
337 p->sock = spdk_sock_listen(p->host, port);
338
339 if (p->sock < 0) {
340 /* if listening failed on any port, do not register the portal group
341 * and close any previously opened. */
342 SPDK_ERRLOG("listen error %.64s:%d\n", p->host, port);
343 rc = -1;
344
345 for (--i; i >= 0; --i) {
346 spdk_sock_close(portal_list[i]->sock);
347 portal_list[i]->sock = -1;
348 }
349
350 break;
351 }
352 }
353
354 if (rc < 0) {
355 spdk_iscsi_portal_grp_destroy(pg);
356 } else {
357 /* Add portals to portal group */
358 for (i = 0; i < num_portals; i++) {
359 spdk_iscsi_portal_grp_add_portal(pg, portal_list[i]);
360 }
361
362 /* Add portal group to the end of the pg list */
363 spdk_iscsi_portal_grp_register(pg);
364 }
365
366 return rc;
367 }
368
369 int
370 spdk_iscsi_portal_grp_create_from_configfile(struct spdk_conf_section *sp)
371 {
372 struct spdk_iscsi_portal_grp *pg;
373 struct spdk_iscsi_portal *p;
374 const char *val;
375 char *label, *portal;
376 int portals = 0, i = 0, rc = 0;
377
378 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "add portal group (from config file) %d\n",
379 spdk_conf_section_get_num(sp));
380
381 val = spdk_conf_section_get_val(sp, "Comment");
382 if (val != NULL) {
383 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "Comment %s\n", val);
384 }
385
386 /* counts number of definitions */
387 for (i = 0; ; i++) {
388 /*
389 * label is no longer used, but we keep it in the config
390 * file definition so that we do not break existing config
391 * files.
392 */
393 label = spdk_conf_section_get_nmval(sp, "Portal", i, 0);
394 portal = spdk_conf_section_get_nmval(sp, "Portal", i, 1);
395 if (label == NULL || portal == NULL)
396 break;
397 rc = spdk_iscsi_portal_create_from_configline(portal, &p, 1);
398 if (rc < 0) {
399 SPDK_ERRLOG("parse portal error (%s)\n", portal);
400 goto error_out;
401 }
402 }
403
404 portals = i;
405 if (portals > MAX_PORTAL) {
406 SPDK_ERRLOG("%d > MAX_PORTAL\n", portals);
407 goto error_out;
408 }
409
410 pg = spdk_iscsi_portal_grp_create(spdk_conf_section_get_num(sp));
411 if (!pg) {
412 SPDK_ERRLOG("portal group malloc error (%s)\n", spdk_conf_section_get_name(sp));
413 goto error_out;
414 }
415
416 for (i = 0; i < portals; i++) {
417 label = spdk_conf_section_get_nmval(sp, "Portal", i, 0);
418 portal = spdk_conf_section_get_nmval(sp, "Portal", i, 1);
419 if (label == NULL || portal == NULL) {
420 spdk_iscsi_portal_grp_destroy(pg);
421 SPDK_ERRLOG("portal error\n");
422 goto error_out;
423 }
424
425 rc = spdk_iscsi_portal_create_from_configline(portal, &p, 0);
426 if (rc < 0) {
427 spdk_iscsi_portal_grp_destroy(pg);
428 SPDK_ERRLOG("parse portal error (%s)\n", portal);
429 goto error_out;
430 }
431
432 SPDK_TRACELOG(SPDK_TRACE_DEBUG,
433 "RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
434 i, p->host, p->port, spdk_conf_section_get_num(sp));
435
436 spdk_iscsi_portal_grp_add_portal(pg, p);
437 }
438
439 /* Add portal group to the end of the pg list */
440 spdk_iscsi_portal_grp_register(pg);
441
442 return 0;
443
444 error_out:
445 return -1;
446 }
447
448 void
449 spdk_iscsi_portal_grp_add_portal(struct spdk_iscsi_portal_grp *pg,
450 struct spdk_iscsi_portal *p)
451 {
452 assert(pg != NULL);
453 assert(p != NULL);
454
455 p->group = pg;
456 TAILQ_INSERT_TAIL(&pg->head, p, tailq);
457 }
458
459 struct spdk_iscsi_portal_grp *
460 spdk_iscsi_portal_grp_find_by_tag(int tag)
461 {
462 struct spdk_iscsi_portal_grp *pg;
463
464 TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
465 if (pg->tag == tag) {
466 return pg;
467 }
468 }
469
470 return NULL;
471 }
472
473 int
474 spdk_iscsi_portal_grp_array_create(void)
475 {
476 int rc = 0;
477 struct spdk_conf_section *sp;
478
479 TAILQ_INIT(&g_spdk_iscsi.pg_head);
480 sp = spdk_conf_first_section(NULL);
481 while (sp != NULL) {
482 if (spdk_conf_section_match_prefix(sp, "PortalGroup")) {
483 if (spdk_conf_section_get_num(sp) == 0) {
484 SPDK_ERRLOG("Group 0 is invalid\n");
485 return -1;
486 }
487
488 /* Build portal group from cfg section PortalGroup */
489 rc = spdk_iscsi_portal_grp_create_from_configfile(sp);
490 if (rc < 0) {
491 SPDK_ERRLOG("parse_portal_group() failed\n");
492 return -1;
493 }
494 }
495 sp = spdk_conf_next_section(sp);
496 }
497 return 0;
498 }
499
500 void
501 spdk_iscsi_portal_grp_array_destroy(void)
502 {
503 struct spdk_iscsi_portal_grp *pg, *tmp;
504
505 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_iscsi_portal_grp_array_destroy\n");
506 pthread_mutex_lock(&g_spdk_iscsi.mutex);
507 TAILQ_FOREACH_SAFE(pg, &g_spdk_iscsi.pg_head, tailq, tmp) {
508 pg->state = GROUP_DESTROY;
509 TAILQ_REMOVE(&g_spdk_iscsi.pg_head, pg, tailq);
510 spdk_iscsi_portal_grp_destroy(pg);
511 }
512 pthread_mutex_unlock(&g_spdk_iscsi.mutex);
513 }
514
515 static int
516 spdk_iscsi_portal_grp_open(struct spdk_iscsi_portal_grp *pg)
517 {
518 struct spdk_iscsi_portal *p;
519 int port;
520 int sock;
521
522 TAILQ_FOREACH(p, &pg->head, tailq) {
523 if (p->sock < 0) {
524 SPDK_TRACELOG(SPDK_TRACE_NET, "open host %s, port %s, tag %d\n",
525 p->host, p->port, pg->tag);
526 port = (int)strtol(p->port, NULL, 0);
527 sock = spdk_sock_listen(p->host, port);
528 if (sock < 0) {
529 SPDK_ERRLOG("listen error %.64s:%d\n", p->host, port);
530 return -1;
531 }
532 p->sock = sock;
533 }
534 }
535 return 0;
536 }
537
538 int
539 spdk_iscsi_portal_grp_open_all(void)
540 {
541 struct spdk_iscsi_portal_grp *pg;
542 int rc;
543
544 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_iscsi_portal_grp_open_all\n");
545 pthread_mutex_lock(&g_spdk_iscsi.mutex);
546 TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
547 rc = spdk_iscsi_portal_grp_open(pg);
548 if (rc < 0) {
549 pthread_mutex_unlock(&g_spdk_iscsi.mutex);
550 return -1;
551 }
552 }
553 pthread_mutex_unlock(&g_spdk_iscsi.mutex);
554 return 0;
555 }
556
557 static int
558 spdk_iscsi_portal_grp_close(struct spdk_iscsi_portal_grp *pg)
559 {
560 struct spdk_iscsi_portal *p;
561
562 TAILQ_FOREACH(p, &pg->head, tailq) {
563 if (p->sock >= 0) {
564 SPDK_TRACELOG(SPDK_TRACE_NET, "close host %s, port %s, tag %d\n",
565 p->host, p->port, pg->tag);
566 close(p->sock);
567 p->sock = -1;
568 }
569 }
570 return 0;
571 }
572
573 int
574 spdk_iscsi_portal_grp_close_all(void)
575 {
576 struct spdk_iscsi_portal_grp *pg;
577 int rc;
578
579 SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_iscsi_portal_grp_close_all\n");
580 pthread_mutex_lock(&g_spdk_iscsi.mutex);
581 TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
582 rc = spdk_iscsi_portal_grp_close(pg);
583 if (rc < 0) {
584 pthread_mutex_unlock(&g_spdk_iscsi.mutex);
585 return -1;
586 }
587 }
588 pthread_mutex_unlock(&g_spdk_iscsi.mutex);
589 return 0;
590 }
591
592 static inline void
593 spdk_iscsi_portal_grp_unregister(struct spdk_iscsi_portal_grp *pg)
594 {
595 struct spdk_iscsi_portal_grp *portal_group;
596 struct spdk_iscsi_portal_grp *portal_group_tmp;
597
598 assert(pg != NULL);
599 assert(!TAILQ_EMPTY(&pg->head));
600
601 pthread_mutex_lock(&g_spdk_iscsi.mutex);
602 TAILQ_FOREACH_SAFE(portal_group, &g_spdk_iscsi.pg_head, tailq, portal_group_tmp) {
603 if (portal_group->tag == pg->tag)
604 TAILQ_REMOVE(&g_spdk_iscsi.pg_head, portal_group, tailq);
605 }
606 pthread_mutex_unlock(&g_spdk_iscsi.mutex);
607 }
608
609 int
610 spdk_iscsi_portal_grp_deletable(int tag)
611 {
612 int ret = 0;
613 struct spdk_iscsi_portal_grp *pg;
614
615 pthread_mutex_lock(&g_spdk_iscsi.mutex);
616 pg = spdk_iscsi_portal_grp_find_by_tag(tag);
617 if (pg == NULL) {
618 ret = -1;
619 goto out;
620 }
621
622 if (pg->state != GROUP_READY) {
623 ret = -1;
624 goto out;
625 }
626
627 if (pg->ref == 0) {
628 ret = 0;
629 goto out;
630 }
631
632 out:
633 if (ret == 0)
634 pg->state = GROUP_DESTROY;
635 pthread_mutex_unlock(&g_spdk_iscsi.mutex);
636 return ret;
637 }
638
639 void
640 spdk_iscsi_portal_grp_release(struct spdk_iscsi_portal_grp *pg)
641 {
642 spdk_iscsi_portal_grp_close(pg);
643 spdk_iscsi_portal_grp_unregister(pg);
644 pthread_mutex_lock(&g_spdk_iscsi.mutex);
645 spdk_iscsi_portal_grp_destroy(pg);
646 pthread_mutex_unlock(&g_spdk_iscsi.mutex);
647 }
648
649 SPDK_LOG_REGISTER_TRACE_FLAG("net", SPDK_TRACE_NET)