xref: /spdk/lib/iscsi/portal_grp.c (revision eb8b1e20a9c8a6bc79f32fde8693d2791a74c34d)
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 "spdk/stdinc.h"
36 
37 #include "spdk/conf.h"
38 #include "spdk/net.h"
39 
40 #include "spdk_internal/log.h"
41 
42 #include "iscsi/iscsi.h"
43 #include "iscsi/tgt_node.h"
44 #include "iscsi/conn.h"
45 #include "iscsi/portal_grp.h"
46 #include "iscsi/acceptor.h"
47 
48 #define PORTNUMSTRLEN 32
49 
50 static int
51 spdk_iscsi_portal_grp_open(struct spdk_iscsi_portal_grp *pg);
52 
53 static struct spdk_iscsi_portal *
54 spdk_iscsi_portal_find_by_addr(const char *host, const char *port)
55 {
56 	struct spdk_iscsi_portal *p;
57 
58 	TAILQ_FOREACH(p, &g_spdk_iscsi.portal_head, g_tailq) {
59 		if (!strcmp(p->host, host) && !strcmp(p->port, port)) {
60 			return p;
61 		}
62 	}
63 
64 	return NULL;
65 }
66 
67 /* Assumes caller allocated host and port strings on the heap */
68 struct spdk_iscsi_portal *
69 spdk_iscsi_portal_create(const char *host, const char *port, uint64_t cpumask)
70 {
71 	struct spdk_iscsi_portal *p = NULL;
72 
73 	assert(host != NULL);
74 	assert(port != NULL);
75 
76 	p = spdk_iscsi_portal_find_by_addr(host, port);
77 	if (p != NULL) {
78 		SPDK_ERRLOG("portal (%s, %s) already exists\n", host, port);
79 		return NULL;
80 	}
81 
82 	p = malloc(sizeof(*p));
83 	if (!p) {
84 		SPDK_ERRLOG("portal malloc error (%s, %s)\n", host, port);
85 		return NULL;
86 	}
87 	p->host = strdup(host);
88 	p->port = strdup(port);
89 	p->cpumask = cpumask;
90 	p->sock = -1;
91 	p->group = NULL; /* set at a later time by caller */
92 	p->acceptor_poller = NULL;
93 
94 	TAILQ_INSERT_TAIL(&g_spdk_iscsi.portal_head, p, g_tailq);
95 
96 	return p;
97 }
98 
99 void
100 spdk_iscsi_portal_destroy(struct spdk_iscsi_portal *p)
101 {
102 	assert(p != NULL);
103 
104 	SPDK_DEBUGLOG(SPDK_TRACE_ISCSI, "spdk_iscsi_portal_destroy\n");
105 	TAILQ_REMOVE(&g_spdk_iscsi.portal_head, p, g_tailq);
106 	free(p->host);
107 	free(p->port);
108 	free(p);
109 }
110 
111 static int
112 spdk_iscsi_portal_open(struct spdk_iscsi_portal *p)
113 {
114 	int port, sock;
115 
116 	if (p->sock >= 0) {
117 		SPDK_ERRLOG("portal (%s, %s) is already opened\n",
118 			    p->host, p->port);
119 		return -1;
120 	}
121 
122 	port = (int)strtol(p->port, NULL, 0);
123 	sock = spdk_sock_listen(p->host, port);
124 	if (sock < 0) {
125 		SPDK_ERRLOG("listen error %.64s.%d\n", p->host, port);
126 		return -1;
127 	}
128 
129 	p->sock = sock;
130 
131 	spdk_iscsi_acceptor_start(p);
132 
133 	return 0;
134 }
135 
136 static void
137 spdk_iscsi_portal_close(struct spdk_iscsi_portal *p)
138 {
139 	if (p->sock >= 0) {
140 		SPDK_DEBUGLOG(SPDK_TRACE_NET, "close portal (%s, %s)\n",
141 			      p->host, p->port);
142 		spdk_iscsi_acceptor_stop(p);
143 		close(p->sock);
144 		p->sock = -1;
145 	}
146 }
147 
148 static int
149 spdk_iscsi_portal_create_from_configline(const char *portalstring,
150 		struct spdk_iscsi_portal **ip,
151 		int dry_run)
152 {
153 	char *host = NULL, *port = NULL;
154 	const char *cpumask_str;
155 	uint64_t cpumask = 0;
156 
157 	int n, len, rc = -1;
158 	const char *p, *q;
159 
160 	if (portalstring == NULL) {
161 		SPDK_ERRLOG("portal error\n");
162 		goto error_out;
163 	}
164 
165 	if (portalstring[0] == '[') {
166 		/* IPv6 */
167 		p = strchr(portalstring + 1, ']');
168 		if (p == NULL) {
169 			SPDK_ERRLOG("portal error\n");
170 			goto error_out;
171 		}
172 		p++;
173 		n = p - portalstring;
174 		if (!dry_run) {
175 			host = malloc(n + 1);
176 			if (!host) {
177 				perror("host");
178 				goto error_out;
179 			}
180 			memcpy(host, portalstring, n);
181 			host[n] = '\0';
182 		}
183 		if (p[0] == '\0') {
184 			if (!dry_run) {
185 				port = malloc(PORTNUMSTRLEN);
186 				if (!port) {
187 					perror("port");
188 					goto error_out;
189 				}
190 				snprintf(port, PORTNUMSTRLEN, "%d", DEFAULT_PORT);
191 			}
192 		} else {
193 			if (p[0] != ':') {
194 				SPDK_ERRLOG("portal error\n");
195 				goto error_out;
196 			}
197 			if (!dry_run) {
198 				q = strchr(portalstring, '@');
199 				if (q == NULL) {
200 					q = portalstring + strlen(portalstring);
201 				}
202 				len = q - p - 1;
203 
204 				port = malloc(len + 1);
205 				if (!port) {
206 					perror("port");
207 					goto error_out;
208 				}
209 				memset(port, 0, len + 1);
210 				memcpy(port, p + 1, len);
211 			}
212 		}
213 	} else {
214 		/* IPv4 */
215 		p = strchr(portalstring, ':');
216 		if (p == NULL) {
217 			p = portalstring + strlen(portalstring);
218 		}
219 		n = p - portalstring;
220 		if (!dry_run) {
221 			host = malloc(n + 1);
222 			if (!host) {
223 				perror("host");
224 				goto error_out;
225 			}
226 			memcpy(host, portalstring, n);
227 			host[n] = '\0';
228 		}
229 		if (p[0] == '\0') {
230 			if (!dry_run) {
231 				port = malloc(PORTNUMSTRLEN);
232 				if (!port) {
233 					perror("port");
234 					goto error_out;
235 				}
236 				snprintf(port, PORTNUMSTRLEN, "%d", DEFAULT_PORT);
237 			}
238 		} else {
239 			if (p[0] != ':') {
240 				SPDK_ERRLOG("portal error\n");
241 				goto error_out;
242 			}
243 			if (!dry_run) {
244 				q = strchr(portalstring, '@');
245 				if (q == NULL) {
246 					q = portalstring + strlen(portalstring);
247 				}
248 
249 				if (q == p) {
250 					SPDK_ERRLOG("no port specified\n");
251 					goto error_out;
252 				}
253 
254 				len = q - p - 1;
255 				port = malloc(len + 1);
256 				if (!port) {
257 					perror("port");
258 					goto error_out;
259 				}
260 				memset(port, 0, len + 1);
261 				memcpy(port, p + 1, len);
262 			}
263 
264 		}
265 	}
266 
267 	p = strchr(portalstring, '@');
268 	if (p != NULL) {
269 		cpumask_str = p + 1;
270 		if (spdk_app_parse_core_mask(cpumask_str, &cpumask)) {
271 			SPDK_ERRLOG("invalid portal cpumask %s\n", cpumask_str);
272 			goto error_out;
273 		}
274 		if ((cpumask & spdk_app_get_core_mask()) != cpumask) {
275 			SPDK_ERRLOG("portal cpumask %s not a subset of "
276 				    "reactor mask %jx\n", cpumask_str,
277 				    spdk_app_get_core_mask());
278 			goto error_out;
279 		}
280 	} else {
281 		cpumask = spdk_app_get_core_mask();
282 	}
283 
284 	if (!dry_run) {
285 		*ip = spdk_iscsi_portal_create(host, port, cpumask);
286 		if (!*ip) {
287 			goto error_out;
288 		}
289 	}
290 
291 	rc = 0;
292 error_out:
293 	free(host);
294 	free(port);
295 
296 	return rc;
297 }
298 
299 struct spdk_iscsi_portal_grp *
300 spdk_iscsi_portal_grp_create(int tag)
301 {
302 	struct spdk_iscsi_portal_grp *pg = malloc(sizeof(*pg));
303 
304 	if (!pg) {
305 		SPDK_ERRLOG("portal group malloc error (%d)\n", tag);
306 		return NULL;
307 	}
308 
309 	/* Make sure there are no duplicate portal group tags */
310 	if (spdk_iscsi_portal_grp_find_by_tag(tag)) {
311 		SPDK_ERRLOG("portal group creation failed.  duplicate portal group tag (%d)\n", tag);
312 		free(pg);
313 		return NULL;
314 	}
315 
316 	pg->state = GROUP_INIT;
317 	pg->ref = 0;
318 	pg->tag = tag;
319 
320 	TAILQ_INIT(&pg->head);
321 
322 	return pg;
323 }
324 
325 void
326 spdk_iscsi_portal_grp_destroy(struct spdk_iscsi_portal_grp *pg)
327 {
328 	struct spdk_iscsi_portal	*p;
329 
330 	assert(pg != NULL);
331 
332 	SPDK_DEBUGLOG(SPDK_TRACE_ISCSI, "spdk_iscsi_portal_grp_destroy\n");
333 	while (!TAILQ_EMPTY(&pg->head)) {
334 		p = TAILQ_FIRST(&pg->head);
335 		TAILQ_REMOVE(&pg->head, p, per_pg_tailq);
336 		spdk_iscsi_portal_destroy(p);
337 	}
338 	free(pg);
339 }
340 
341 static void
342 spdk_iscsi_portal_grp_register(struct spdk_iscsi_portal_grp *pg)
343 {
344 	assert(pg != NULL);
345 	assert(!TAILQ_EMPTY(&pg->head));
346 
347 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
348 	pg->state = GROUP_READY;
349 	TAILQ_INSERT_TAIL(&g_spdk_iscsi.pg_head, pg, tailq);
350 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
351 }
352 
353 /**
354  * If all portals are valid, this function will take their ownership.
355  */
356 int
357 spdk_iscsi_portal_grp_create_from_portal_list(int tag,
358 		struct spdk_iscsi_portal **portal_list,
359 		int num_portals)
360 {
361 	int i = 0, rc = 0;
362 	struct spdk_iscsi_portal_grp *pg;
363 
364 	SPDK_DEBUGLOG(SPDK_TRACE_ISCSI, "add portal group (from portal list) %d\n", tag);
365 
366 	if (num_portals > MAX_PORTAL) {
367 		SPDK_ERRLOG("%d > MAX_PORTAL\n", num_portals);
368 		return -1;
369 	}
370 
371 	pg = spdk_iscsi_portal_grp_create(tag);
372 	if (!pg) {
373 		SPDK_ERRLOG("portal group creation error (%d)\n", tag);
374 		return -1;
375 	}
376 
377 	for (i = 0; i < num_portals; i++) {
378 		struct spdk_iscsi_portal *p = portal_list[i];
379 
380 		SPDK_DEBUGLOG(SPDK_TRACE_ISCSI,
381 			      "RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
382 			      i, p->host, p->port, tag);
383 		rc = spdk_iscsi_portal_open(p);
384 		if (rc < 0) {
385 			/* if listening failed on any port, do not register the portal group
386 			 * and close any previously opened. */
387 			for (--i; i >= 0; --i) {
388 				spdk_iscsi_portal_close(portal_list[i]);
389 			}
390 
391 			break;
392 		}
393 	}
394 
395 	if (rc < 0) {
396 		spdk_iscsi_portal_grp_destroy(pg);
397 	} else {
398 		/* Add portals to portal group */
399 		for (i = 0; i < num_portals; i++) {
400 			spdk_iscsi_portal_grp_add_portal(pg, portal_list[i]);
401 		}
402 
403 		/* Add portal group to the end of the pg list */
404 		spdk_iscsi_portal_grp_register(pg);
405 	}
406 
407 	return rc;
408 }
409 
410 int
411 spdk_iscsi_portal_grp_create_from_configfile(struct spdk_conf_section *sp)
412 {
413 	struct spdk_iscsi_portal_grp *pg;
414 	struct spdk_iscsi_portal	*p;
415 	const char *val;
416 	char *label, *portal;
417 	int portals = 0, i = 0, rc = 0;
418 
419 	SPDK_DEBUGLOG(SPDK_TRACE_ISCSI, "add portal group (from config file) %d\n",
420 		      spdk_conf_section_get_num(sp));
421 
422 	val = spdk_conf_section_get_val(sp, "Comment");
423 	if (val != NULL) {
424 		SPDK_DEBUGLOG(SPDK_TRACE_ISCSI, "Comment %s\n", val);
425 	}
426 
427 	/* counts number of definitions */
428 	for (i = 0; ; i++) {
429 		/*
430 		 * label is no longer used, but we keep it in the config
431 		 *  file definition so that we do not break existing config
432 		 *  files.
433 		 */
434 		label = spdk_conf_section_get_nmval(sp, "Portal", i, 0);
435 		portal = spdk_conf_section_get_nmval(sp, "Portal", i, 1);
436 		if (label == NULL || portal == NULL)
437 			break;
438 		rc = spdk_iscsi_portal_create_from_configline(portal, &p, 1);
439 		if (rc < 0) {
440 			SPDK_ERRLOG("parse portal error (%s)\n", portal);
441 			goto error_out;
442 		}
443 	}
444 
445 	portals = i;
446 	if (portals > MAX_PORTAL) {
447 		SPDK_ERRLOG("%d > MAX_PORTAL\n", portals);
448 		goto error_out;
449 	}
450 
451 	pg = spdk_iscsi_portal_grp_create(spdk_conf_section_get_num(sp));
452 	if (!pg) {
453 		SPDK_ERRLOG("portal group malloc error (%s)\n", spdk_conf_section_get_name(sp));
454 		goto error_out;
455 	}
456 
457 	for (i = 0; i < portals; i++) {
458 		label = spdk_conf_section_get_nmval(sp, "Portal", i, 0);
459 		portal = spdk_conf_section_get_nmval(sp, "Portal", i, 1);
460 		if (label == NULL || portal == NULL) {
461 			spdk_iscsi_portal_grp_destroy(pg);
462 			SPDK_ERRLOG("portal error\n");
463 			goto error_out;
464 		}
465 
466 		rc = spdk_iscsi_portal_create_from_configline(portal, &p, 0);
467 		if (rc < 0) {
468 			spdk_iscsi_portal_grp_destroy(pg);
469 			SPDK_ERRLOG("parse portal error (%s)\n", portal);
470 			goto error_out;
471 		}
472 
473 		SPDK_DEBUGLOG(SPDK_TRACE_ISCSI,
474 			      "RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
475 			      i, p->host, p->port, spdk_conf_section_get_num(sp));
476 
477 		spdk_iscsi_portal_grp_add_portal(pg, p);
478 	}
479 
480 	/* Add portal group to the end of the pg list */
481 	spdk_iscsi_portal_grp_register(pg);
482 
483 	return 0;
484 
485 error_out:
486 	return -1;
487 }
488 
489 void
490 spdk_iscsi_portal_grp_add_portal(struct spdk_iscsi_portal_grp *pg,
491 				 struct spdk_iscsi_portal *p)
492 {
493 	assert(pg != NULL);
494 	assert(p != NULL);
495 
496 	p->group = pg;
497 	TAILQ_INSERT_TAIL(&pg->head, p, per_pg_tailq);
498 }
499 
500 struct spdk_iscsi_portal_grp *
501 spdk_iscsi_portal_grp_find_by_tag(int tag)
502 {
503 	struct spdk_iscsi_portal_grp *pg;
504 
505 	TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
506 		if (pg->tag == tag) {
507 			return pg;
508 		}
509 	}
510 
511 	return NULL;
512 }
513 
514 int
515 spdk_iscsi_portal_grp_array_create(void)
516 {
517 	int rc = 0;
518 	struct spdk_conf_section *sp;
519 
520 	TAILQ_INIT(&g_spdk_iscsi.portal_head);
521 	TAILQ_INIT(&g_spdk_iscsi.pg_head);
522 	sp = spdk_conf_first_section(NULL);
523 	while (sp != NULL) {
524 		if (spdk_conf_section_match_prefix(sp, "PortalGroup")) {
525 			if (spdk_conf_section_get_num(sp) == 0) {
526 				SPDK_ERRLOG("Group 0 is invalid\n");
527 				return -1;
528 			}
529 
530 			/* Build portal group from cfg section PortalGroup */
531 			rc = spdk_iscsi_portal_grp_create_from_configfile(sp);
532 			if (rc < 0) {
533 				SPDK_ERRLOG("parse_portal_group() failed\n");
534 				return -1;
535 			}
536 		}
537 		sp = spdk_conf_next_section(sp);
538 	}
539 	return 0;
540 }
541 
542 void
543 spdk_iscsi_portal_grp_array_destroy(void)
544 {
545 	struct spdk_iscsi_portal_grp *pg, *tmp;
546 
547 	SPDK_DEBUGLOG(SPDK_TRACE_ISCSI, "spdk_iscsi_portal_grp_array_destroy\n");
548 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
549 	TAILQ_FOREACH_SAFE(pg, &g_spdk_iscsi.pg_head, tailq, tmp) {
550 		pg->state = GROUP_DESTROY;
551 		TAILQ_REMOVE(&g_spdk_iscsi.pg_head, pg, tailq);
552 		spdk_iscsi_portal_grp_destroy(pg);
553 	}
554 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
555 }
556 
557 static int
558 spdk_iscsi_portal_grp_open(struct spdk_iscsi_portal_grp *pg)
559 {
560 	struct spdk_iscsi_portal *p;
561 	int rc;
562 
563 	TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
564 		rc = spdk_iscsi_portal_open(p);
565 		if (rc < 0) {
566 			return rc;
567 		}
568 	}
569 	return 0;
570 }
571 
572 int
573 spdk_iscsi_portal_grp_open_all(void)
574 {
575 	struct spdk_iscsi_portal_grp *pg;
576 	int rc;
577 
578 	SPDK_DEBUGLOG(SPDK_TRACE_ISCSI, "spdk_iscsi_portal_grp_open_all\n");
579 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
580 	TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
581 		rc = spdk_iscsi_portal_grp_open(pg);
582 		if (rc < 0) {
583 			pthread_mutex_unlock(&g_spdk_iscsi.mutex);
584 			return -1;
585 		}
586 	}
587 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
588 	return 0;
589 }
590 
591 static void
592 spdk_iscsi_portal_grp_close(struct spdk_iscsi_portal_grp *pg)
593 {
594 	struct spdk_iscsi_portal *p;
595 
596 	TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
597 		spdk_iscsi_portal_close(p);
598 	}
599 }
600 
601 void
602 spdk_iscsi_portal_grp_close_all(void)
603 {
604 	struct spdk_iscsi_portal_grp *pg;
605 
606 	SPDK_DEBUGLOG(SPDK_TRACE_ISCSI, "spdk_iscsi_portal_grp_close_all\n");
607 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
608 	TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
609 		spdk_iscsi_portal_grp_close(pg);
610 	}
611 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
612 }
613 
614 static inline void
615 spdk_iscsi_portal_grp_unregister(struct spdk_iscsi_portal_grp *pg)
616 {
617 	struct spdk_iscsi_portal_grp *portal_group;
618 	struct spdk_iscsi_portal_grp *portal_group_tmp;
619 
620 	assert(pg != NULL);
621 	assert(!TAILQ_EMPTY(&pg->head));
622 
623 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
624 	TAILQ_FOREACH_SAFE(portal_group, &g_spdk_iscsi.pg_head, tailq, portal_group_tmp) {
625 		if (portal_group->tag == pg->tag)
626 			TAILQ_REMOVE(&g_spdk_iscsi.pg_head, portal_group, tailq);
627 	}
628 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
629 }
630 
631 void
632 spdk_iscsi_portal_grp_release(struct spdk_iscsi_portal_grp *pg)
633 {
634 	spdk_iscsi_portal_grp_close(pg);
635 	spdk_iscsi_portal_grp_unregister(pg);
636 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
637 	spdk_iscsi_portal_grp_destroy(pg);
638 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
639 }
640