]>
git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/iscsi/portal_grp.c
4 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5 * Copyright (c) Intel Corporation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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.
35 #include "spdk/stdinc.h"
37 #include "spdk/conf.h"
38 #include "spdk/sock.h"
39 #include "spdk/event.h"
40 #include "spdk/string.h"
42 #include "spdk_internal/log.h"
44 #include "iscsi/iscsi.h"
45 #include "iscsi/conn.h"
46 #include "iscsi/portal_grp.h"
47 #include "iscsi/acceptor.h"
49 #define PORTNUMSTRLEN 32
51 static struct spdk_iscsi_portal
*
52 spdk_iscsi_portal_find_by_addr(const char *host
, const char *port
)
54 struct spdk_iscsi_portal
*p
;
56 TAILQ_FOREACH(p
, &g_spdk_iscsi
.portal_head
, g_tailq
) {
57 if (!strcmp(p
->host
, host
) && !strcmp(p
->port
, port
)) {
65 /* Assumes caller allocated host and port strings on the heap */
66 struct spdk_iscsi_portal
*
67 spdk_iscsi_portal_create(const char *host
, const char *port
, const char *cpumask
)
69 struct spdk_iscsi_portal
*p
= NULL
, *tmp
;
70 struct spdk_cpuset
*core_mask
= NULL
;
77 p
= calloc(1, sizeof(*p
));
79 SPDK_ERRLOG("calloc() failed for portal\n");
83 /* check and overwrite abbreviation of wildcard */
84 if (strcasecmp(host
, "[*]") == 0) {
85 SPDK_WARNLOG("Please use \"[::]\" as IPv6 wildcard\n");
86 SPDK_WARNLOG("Convert \"[*]\" to \"[::]\" automatically\n");
87 SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)");
88 p
->host
= strdup("[::]");
89 } else if (strcasecmp(host
, "*") == 0) {
90 SPDK_WARNLOG("Please use \"0.0.0.0\" as IPv4 wildcard\n");
91 SPDK_WARNLOG("Convert \"*\" to \"0.0.0.0\" automatically\n");
92 SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)");
93 p
->host
= strdup("0.0.0.0");
95 p
->host
= strdup(host
);
98 SPDK_ERRLOG("strdup() failed for host\n");
102 p
->port
= strdup(port
);
104 SPDK_ERRLOG("strdup() failed for host\n");
108 core_mask
= spdk_cpuset_alloc();
110 SPDK_ERRLOG("spdk_cpuset_alloc() failed for host\n");
114 if (cpumask
!= NULL
) {
115 rc
= spdk_app_parse_core_mask(cpumask
, core_mask
);
117 SPDK_ERRLOG("cpumask (%s) is invalid\n", cpumask
);
120 if (spdk_cpuset_count(core_mask
) == 0) {
121 SPDK_ERRLOG("cpumask (%s) does not contain core mask (0x%s)\n",
122 cpumask
, spdk_cpuset_fmt(spdk_app_get_core_mask()));
126 spdk_cpuset_copy(core_mask
, spdk_app_get_core_mask());
129 p
->cpumask
= core_mask
;
132 p
->group
= NULL
; /* set at a later time by caller */
133 p
->acceptor_poller
= NULL
;
135 pthread_mutex_lock(&g_spdk_iscsi
.mutex
);
136 tmp
= spdk_iscsi_portal_find_by_addr(host
, port
);
138 pthread_mutex_unlock(&g_spdk_iscsi
.mutex
);
139 SPDK_ERRLOG("portal (%s, %s) already exists\n", host
, port
);
143 TAILQ_INSERT_TAIL(&g_spdk_iscsi
.portal_head
, p
, g_tailq
);
144 pthread_mutex_unlock(&g_spdk_iscsi
.mutex
);
149 spdk_cpuset_free(core_mask
);
158 spdk_iscsi_portal_destroy(struct spdk_iscsi_portal
*p
)
162 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "spdk_iscsi_portal_destroy\n");
164 pthread_mutex_lock(&g_spdk_iscsi
.mutex
);
165 TAILQ_REMOVE(&g_spdk_iscsi
.portal_head
, p
, g_tailq
);
166 pthread_mutex_unlock(&g_spdk_iscsi
.mutex
);
170 spdk_cpuset_free(p
->cpumask
);
176 spdk_iscsi_portal_open(struct spdk_iscsi_portal
*p
)
178 struct spdk_sock
*sock
;
181 if (p
->sock
!= NULL
) {
182 SPDK_ERRLOG("portal (%s, %s) is already opened\n",
187 port
= (int)strtol(p
->port
, NULL
, 0);
188 sock
= spdk_sock_listen(p
->host
, port
);
190 SPDK_ERRLOG("listen error %.64s.%d\n", p
->host
, port
);
197 * When the portal is created by config file, incoming connection
198 * requests for the socket are pended to accept until reactors start.
199 * However the gap between listen() and accept() will be slight and
200 * the requests will be queued by the nonzero backlog of the socket
203 spdk_iscsi_acceptor_start(p
);
209 spdk_iscsi_portal_close(struct spdk_iscsi_portal
*p
)
212 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "close portal (%s, %s)\n",
214 spdk_iscsi_acceptor_stop(p
);
215 spdk_sock_close(&p
->sock
);
220 spdk_iscsi_parse_portal(const char *portalstring
, struct spdk_iscsi_portal
**ip
,
223 char *host
= NULL
, *port
= NULL
, *cpumask
= NULL
;
227 if (portalstring
== NULL
) {
228 SPDK_ERRLOG("portal error\n");
233 if (portalstring
[0] == '[') {
235 p
= strchr(portalstring
+ 1, ']');
237 SPDK_ERRLOG("portal error\n");
243 p
= strchr(portalstring
, ':');
245 p
= portalstring
+ strlen(portalstring
);
250 len
= p
- portalstring
;
251 host
= malloc(len
+ 1);
253 SPDK_ERRLOG("malloc() failed for host\n");
256 memcpy(host
, portalstring
, len
);
260 /* Port number (IPv4 and IPv6 are the same) */
263 port
= malloc(PORTNUMSTRLEN
);
265 SPDK_ERRLOG("malloc() failed for port\n");
268 snprintf(port
, PORTNUMSTRLEN
, "%d", DEFAULT_PORT
);
272 SPDK_ERRLOG("portal error\n");
275 q
= strchr(portalstring
, '@');
277 q
= portalstring
+ strlen(portalstring
);
280 SPDK_ERRLOG("no port specified\n");
286 port
= malloc(len
+ 1);
288 SPDK_ERRLOG("malloc() failed for port\n");
291 memcpy(port
, p
+ 1, len
);
296 /* Cpumask (IPv4 and IPv6 are the same) */
297 p
= strchr(portalstring
, '@');
299 q
= portalstring
+ strlen(portalstring
);
301 SPDK_ERRLOG("no cpumask specified\n");
306 cpumask
= malloc(len
+ 1);
307 if (cpumask
== NULL
) {
308 SPDK_ERRLOG("malloc() failed for cpumask\n");
311 memcpy(cpumask
, p
+ 1, len
);
317 *ip
= spdk_iscsi_portal_create(host
, port
, cpumask
);
332 struct spdk_iscsi_portal_grp
*
333 spdk_iscsi_portal_grp_create(int tag
)
335 struct spdk_iscsi_portal_grp
*pg
= malloc(sizeof(*pg
));
338 SPDK_ERRLOG("malloc() failed for portal group\n");
345 TAILQ_INIT(&pg
->head
);
351 spdk_iscsi_portal_grp_destroy(struct spdk_iscsi_portal_grp
*pg
)
353 struct spdk_iscsi_portal
*p
;
357 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "spdk_iscsi_portal_grp_destroy\n");
358 while (!TAILQ_EMPTY(&pg
->head
)) {
359 p
= TAILQ_FIRST(&pg
->head
);
360 TAILQ_REMOVE(&pg
->head
, p
, per_pg_tailq
);
361 spdk_iscsi_portal_destroy(p
);
367 spdk_iscsi_portal_grp_register(struct spdk_iscsi_portal_grp
*pg
)
370 struct spdk_iscsi_portal_grp
*tmp
;
374 pthread_mutex_lock(&g_spdk_iscsi
.mutex
);
375 tmp
= spdk_iscsi_portal_grp_find_by_tag(pg
->tag
);
377 TAILQ_INSERT_TAIL(&g_spdk_iscsi
.pg_head
, pg
, tailq
);
380 pthread_mutex_unlock(&g_spdk_iscsi
.mutex
);
385 spdk_iscsi_portal_grp_add_portal(struct spdk_iscsi_portal_grp
*pg
,
386 struct spdk_iscsi_portal
*p
)
392 TAILQ_INSERT_TAIL(&pg
->head
, p
, per_pg_tailq
);
396 spdk_iscsi_parse_portal_grp(struct spdk_conf_section
*sp
)
398 struct spdk_iscsi_portal_grp
*pg
;
399 struct spdk_iscsi_portal
*p
;
401 char *label
, *portal
;
402 int portals
= 0, i
= 0, rc
= 0;
404 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "add portal group (from config file) %d\n",
405 spdk_conf_section_get_num(sp
));
407 val
= spdk_conf_section_get_val(sp
, "Comment");
409 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "Comment %s\n", val
);
412 /* counts number of definitions */
415 * label is no longer used, but we keep it in the config
416 * file definition so that we do not break existing config
419 label
= spdk_conf_section_get_nmval(sp
, "Portal", i
, 0);
420 portal
= spdk_conf_section_get_nmval(sp
, "Portal", i
, 1);
421 if (label
== NULL
|| portal
== NULL
) {
424 rc
= spdk_iscsi_parse_portal(portal
, &p
, 1);
426 SPDK_ERRLOG("parse portal error (%s)\n", portal
);
432 if (portals
> MAX_PORTAL
) {
433 SPDK_ERRLOG("%d > MAX_PORTAL\n", portals
);
437 pg
= spdk_iscsi_portal_grp_create(spdk_conf_section_get_num(sp
));
439 SPDK_ERRLOG("portal group malloc error (%s)\n", spdk_conf_section_get_name(sp
));
443 for (i
= 0; i
< portals
; i
++) {
444 label
= spdk_conf_section_get_nmval(sp
, "Portal", i
, 0);
445 portal
= spdk_conf_section_get_nmval(sp
, "Portal", i
, 1);
446 if (label
== NULL
|| portal
== NULL
) {
447 SPDK_ERRLOG("portal error\n");
451 rc
= spdk_iscsi_parse_portal(portal
, &p
, 0);
453 SPDK_ERRLOG("parse portal error (%s)\n", portal
);
457 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
,
458 "RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
459 i
, p
->host
, p
->port
, spdk_conf_section_get_num(sp
));
461 spdk_iscsi_portal_grp_add_portal(pg
, p
);
464 rc
= spdk_iscsi_portal_grp_open(pg
);
466 SPDK_ERRLOG("portal_grp_open failed\n");
470 /* Add portal group to the end of the pg list */
471 rc
= spdk_iscsi_portal_grp_register(pg
);
473 SPDK_ERRLOG("register portal failed\n");
480 spdk_iscsi_portal_grp_release(pg
);
484 struct spdk_iscsi_portal_grp
*
485 spdk_iscsi_portal_grp_find_by_tag(int tag
)
487 struct spdk_iscsi_portal_grp
*pg
;
489 TAILQ_FOREACH(pg
, &g_spdk_iscsi
.pg_head
, tailq
) {
490 if (pg
->tag
== tag
) {
499 spdk_iscsi_parse_portal_grps(void)
502 struct spdk_conf_section
*sp
;
504 sp
= spdk_conf_first_section(NULL
);
506 if (spdk_conf_section_match_prefix(sp
, "PortalGroup")) {
507 if (spdk_conf_section_get_num(sp
) == 0) {
508 SPDK_ERRLOG("Group 0 is invalid\n");
512 /* Build portal group from cfg section PortalGroup */
513 rc
= spdk_iscsi_parse_portal_grp(sp
);
515 SPDK_ERRLOG("parse_portal_group() failed\n");
519 sp
= spdk_conf_next_section(sp
);
525 spdk_iscsi_portal_grps_destroy(void)
527 struct spdk_iscsi_portal_grp
*pg
;
529 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "spdk_iscsi_portal_grps_destroy\n");
530 pthread_mutex_lock(&g_spdk_iscsi
.mutex
);
531 while (!TAILQ_EMPTY(&g_spdk_iscsi
.pg_head
)) {
532 pg
= TAILQ_FIRST(&g_spdk_iscsi
.pg_head
);
533 TAILQ_REMOVE(&g_spdk_iscsi
.pg_head
, pg
, tailq
);
534 pthread_mutex_unlock(&g_spdk_iscsi
.mutex
);
535 spdk_iscsi_portal_grp_destroy(pg
);
536 pthread_mutex_lock(&g_spdk_iscsi
.mutex
);
538 pthread_mutex_unlock(&g_spdk_iscsi
.mutex
);
542 spdk_iscsi_portal_grp_open(struct spdk_iscsi_portal_grp
*pg
)
544 struct spdk_iscsi_portal
*p
;
547 TAILQ_FOREACH(p
, &pg
->head
, per_pg_tailq
) {
548 rc
= spdk_iscsi_portal_open(p
);
557 spdk_iscsi_portal_grp_close(struct spdk_iscsi_portal_grp
*pg
)
559 struct spdk_iscsi_portal
*p
;
561 TAILQ_FOREACH(p
, &pg
->head
, per_pg_tailq
) {
562 spdk_iscsi_portal_close(p
);
567 spdk_iscsi_portal_grp_close_all(void)
569 struct spdk_iscsi_portal_grp
*pg
;
571 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "spdk_iscsi_portal_grp_close_all\n");
572 pthread_mutex_lock(&g_spdk_iscsi
.mutex
);
573 TAILQ_FOREACH(pg
, &g_spdk_iscsi
.pg_head
, tailq
) {
574 spdk_iscsi_portal_grp_close(pg
);
576 pthread_mutex_unlock(&g_spdk_iscsi
.mutex
);
579 struct spdk_iscsi_portal_grp
*
580 spdk_iscsi_portal_grp_unregister(int tag
)
582 struct spdk_iscsi_portal_grp
*pg
;
584 pthread_mutex_lock(&g_spdk_iscsi
.mutex
);
585 TAILQ_FOREACH(pg
, &g_spdk_iscsi
.pg_head
, tailq
) {
586 if (pg
->tag
== tag
) {
587 TAILQ_REMOVE(&g_spdk_iscsi
.pg_head
, pg
, tailq
);
588 pthread_mutex_unlock(&g_spdk_iscsi
.mutex
);
592 pthread_mutex_unlock(&g_spdk_iscsi
.mutex
);
597 spdk_iscsi_portal_grp_release(struct spdk_iscsi_portal_grp
*pg
)
599 spdk_iscsi_portal_grp_close(pg
);
600 spdk_iscsi_portal_grp_destroy(pg
);
603 static const char *portal_group_section
= \
605 "# Users must change the PortalGroup section(s) to match the IP addresses\n"
606 "# for their environment.\n"
607 "# PortalGroup sections define which network portals the iSCSI target\n"
608 "# will use to listen for incoming connections. These are also used to\n"
609 "# determine which targets are accessible over each portal group.\n"
610 "# Up to 1024 Portal directives are allowed. These define the network\n"
611 "# portals of the portal group. The user must specify a IP address\n"
612 "# for each network portal, and may optionally specify a port and\n"
613 "# a cpumask. If the port is omitted, 3260 will be used. Cpumask will\n"
614 "# be used to set the processor affinity of the iSCSI connection\n"
615 "# through the portal. If the cpumask is omitted, cpumask will be\n"
616 "# set to all available processors.\n"
618 "# Portal <Name> <IP address>[:<port>[@<cpumask>]]\n";
620 #define PORTAL_GROUP_TMPL \
621 "[PortalGroup%d]\n" \
622 " Comment \"Portal%d\"\n"
624 #define PORTAL_TMPL \
625 " Portal DA1 %s:%s@0x%s\n"
628 spdk_iscsi_portal_grps_config_text(FILE *fp
)
630 struct spdk_iscsi_portal
*p
= NULL
;
631 struct spdk_iscsi_portal_grp
*pg
= NULL
;
633 /* Create portal group section */
634 fprintf(fp
, "%s", portal_group_section
);
636 /* Dump portal groups */
637 TAILQ_FOREACH(pg
, &g_spdk_iscsi
.pg_head
, tailq
) {
638 if (NULL
== pg
) { continue; }
639 fprintf(fp
, PORTAL_GROUP_TMPL
, pg
->tag
, pg
->tag
);
641 TAILQ_FOREACH(p
, &pg
->head
, per_pg_tailq
) {
642 if (NULL
== p
) { continue; }
643 fprintf(fp
, PORTAL_TMPL
, p
->host
, p
->port
,
644 spdk_cpuset_fmt(p
->cpumask
));
650 spdk_iscsi_portal_grp_info_json(struct spdk_iscsi_portal_grp
*pg
,
651 struct spdk_json_write_ctx
*w
)
653 struct spdk_iscsi_portal
*portal
;
655 spdk_json_write_object_begin(w
);
657 spdk_json_write_named_int32(w
, "tag", pg
->tag
);
659 spdk_json_write_named_array_begin(w
, "portals");
660 TAILQ_FOREACH(portal
, &pg
->head
, per_pg_tailq
) {
661 spdk_json_write_object_begin(w
);
663 spdk_json_write_named_string(w
, "host", portal
->host
);
664 spdk_json_write_named_string(w
, "port", portal
->port
);
665 spdk_json_write_named_string_fmt(w
, "cpumask", "0x%s",
666 spdk_cpuset_fmt(portal
->cpumask
));
668 spdk_json_write_object_end(w
);
670 spdk_json_write_array_end(w
);
672 spdk_json_write_object_end(w
);
676 spdk_iscsi_portal_grp_config_json(struct spdk_iscsi_portal_grp
*pg
,
677 struct spdk_json_write_ctx
*w
)
679 spdk_json_write_object_begin(w
);
681 spdk_json_write_named_string(w
, "method", "add_portal_group");
683 spdk_json_write_name(w
, "params");
684 spdk_iscsi_portal_grp_info_json(pg
, w
);
686 spdk_json_write_object_end(w
);
690 spdk_iscsi_portal_grps_info_json(struct spdk_json_write_ctx
*w
)
692 struct spdk_iscsi_portal_grp
*pg
;
694 TAILQ_FOREACH(pg
, &g_spdk_iscsi
.pg_head
, tailq
) {
695 spdk_iscsi_portal_grp_info_json(pg
, w
);
700 spdk_iscsi_portal_grps_config_json(struct spdk_json_write_ctx
*w
)
702 struct spdk_iscsi_portal_grp
*pg
;
704 TAILQ_FOREACH(pg
, &g_spdk_iscsi
.pg_head
, tailq
) {
705 spdk_iscsi_portal_grp_config_json(pg
, w
);