xref: /spdk/lib/iscsi/init_grp.c (revision b30d57cdad6d2bc75cc1e4e2ebbcebcb0d98dcfa)
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/string.h"
38 
39 #include "spdk/log.h"
40 
41 #include "iscsi/iscsi.h"
42 #include "iscsi/init_grp.h"
43 
44 static struct spdk_iscsi_init_grp *
45 iscsi_init_grp_create(int tag)
46 {
47 	struct spdk_iscsi_init_grp *ig;
48 
49 	ig = calloc(1, sizeof(*ig));
50 	if (ig == NULL) {
51 		SPDK_ERRLOG("calloc() failed for initiator group\n");
52 		return NULL;
53 	}
54 
55 	ig->tag = tag;
56 	TAILQ_INIT(&ig->initiator_head);
57 	TAILQ_INIT(&ig->netmask_head);
58 	return ig;
59 }
60 
61 static struct spdk_iscsi_initiator_name *
62 iscsi_init_grp_find_initiator(struct spdk_iscsi_init_grp *ig, char *name)
63 {
64 	struct spdk_iscsi_initiator_name *iname;
65 
66 	TAILQ_FOREACH(iname, &ig->initiator_head, tailq) {
67 		if (!strcmp(iname->name, name)) {
68 			return iname;
69 		}
70 	}
71 	return NULL;
72 }
73 
74 static int
75 iscsi_init_grp_add_initiator(struct spdk_iscsi_init_grp *ig, char *name)
76 {
77 	struct spdk_iscsi_initiator_name *iname;
78 	char *p;
79 	size_t len;
80 
81 	if (ig->ninitiators >= MAX_INITIATOR) {
82 		SPDK_ERRLOG("> MAX_INITIATOR(=%d) is not allowed\n", MAX_INITIATOR);
83 		return -EPERM;
84 	}
85 
86 	len = strlen(name);
87 	if (len > MAX_INITIATOR_NAME) {
88 		SPDK_ERRLOG("Initiator Name is larger than 223 bytes\n");
89 		return -EINVAL;
90 	}
91 
92 	iname = iscsi_init_grp_find_initiator(ig, name);
93 	if (iname != NULL) {
94 		return -EEXIST;
95 	}
96 
97 	iname = calloc(1, sizeof(*iname));
98 	if (iname == NULL) {
99 		SPDK_ERRLOG("malloc() failed for initiator name str\n");
100 		return -ENOMEM;
101 	}
102 
103 	memcpy(iname->name, name, len);
104 
105 	/* Replace "ALL" by "ANY" if set */
106 	p = strstr(iname->name, "ALL");
107 	if (p != NULL) {
108 		SPDK_WARNLOG("Please use \"%s\" instead of \"%s\"\n", "ANY", "ALL");
109 		SPDK_WARNLOG("Converting \"%s\" to \"%s\" automatically\n", "ALL", "ANY");
110 		memcpy(p, "ANY", 3);
111 	}
112 
113 	TAILQ_INSERT_TAIL(&ig->initiator_head, iname, tailq);
114 	ig->ninitiators++;
115 
116 	SPDK_DEBUGLOG(iscsi, "InitiatorName %s\n", name);
117 	return 0;
118 }
119 
120 static int
121 iscsi_init_grp_delete_initiator(struct spdk_iscsi_init_grp *ig, char *name)
122 {
123 	struct spdk_iscsi_initiator_name *iname;
124 
125 	iname = iscsi_init_grp_find_initiator(ig, name);
126 	if (iname == NULL) {
127 		return -ENOENT;
128 	}
129 
130 	TAILQ_REMOVE(&ig->initiator_head, iname, tailq);
131 	ig->ninitiators--;
132 	free(iname);
133 	return 0;
134 }
135 
136 static int
137 iscsi_init_grp_add_initiators(struct spdk_iscsi_init_grp *ig, int num_inames,
138 			      char **inames)
139 {
140 	int i;
141 	int rc;
142 
143 	for (i = 0; i < num_inames; i++) {
144 		rc = iscsi_init_grp_add_initiator(ig, inames[i]);
145 		if (rc < 0) {
146 			goto cleanup;
147 		}
148 	}
149 	return 0;
150 
151 cleanup:
152 	for (; i > 0; --i) {
153 		iscsi_init_grp_delete_initiator(ig, inames[i - 1]);
154 	}
155 	return rc;
156 }
157 
158 static void
159 iscsi_init_grp_delete_all_initiators(struct spdk_iscsi_init_grp *ig)
160 {
161 	struct spdk_iscsi_initiator_name *iname, *tmp;
162 
163 	TAILQ_FOREACH_SAFE(iname, &ig->initiator_head, tailq, tmp) {
164 		TAILQ_REMOVE(&ig->initiator_head, iname, tailq);
165 		ig->ninitiators--;
166 		free(iname);
167 	}
168 }
169 
170 static int
171 iscsi_init_grp_delete_initiators(struct spdk_iscsi_init_grp *ig, int num_inames, char **inames)
172 {
173 	int i;
174 	int rc;
175 
176 	for (i = 0; i < num_inames; i++) {
177 		rc = iscsi_init_grp_delete_initiator(ig, inames[i]);
178 		if (rc < 0) {
179 			goto cleanup;
180 		}
181 	}
182 	return 0;
183 
184 cleanup:
185 	for (; i > 0; --i) {
186 		rc = iscsi_init_grp_add_initiator(ig, inames[i - 1]);
187 		if (rc != 0) {
188 			iscsi_init_grp_delete_all_initiators(ig);
189 			break;
190 		}
191 	}
192 	return -1;
193 }
194 
195 static struct spdk_iscsi_initiator_netmask *
196 iscsi_init_grp_find_netmask(struct spdk_iscsi_init_grp *ig, const char *mask)
197 {
198 	struct spdk_iscsi_initiator_netmask *netmask;
199 
200 	TAILQ_FOREACH(netmask, &ig->netmask_head, tailq) {
201 		if (!strcmp(netmask->mask, mask)) {
202 			return netmask;
203 		}
204 	}
205 	return NULL;
206 }
207 
208 static int
209 iscsi_init_grp_add_netmask(struct spdk_iscsi_init_grp *ig, char *mask)
210 {
211 	struct spdk_iscsi_initiator_netmask *imask;
212 	char *p;
213 	size_t len;
214 
215 	if (ig->nnetmasks >= MAX_NETMASK) {
216 		SPDK_ERRLOG("> MAX_NETMASK(=%d) is not allowed\n", MAX_NETMASK);
217 		return -EPERM;
218 	}
219 
220 	len = strlen(mask);
221 	if (len > MAX_INITIATOR_ADDR) {
222 		SPDK_ERRLOG("Initiator Name is larger than %d bytes\n", MAX_INITIATOR_ADDR);
223 		return -EINVAL;
224 	}
225 
226 	imask = iscsi_init_grp_find_netmask(ig, mask);
227 	if (imask != NULL) {
228 		return -EEXIST;
229 	}
230 
231 	imask = calloc(1, sizeof(*imask));
232 	if (imask == NULL) {
233 		SPDK_ERRLOG("malloc() failed for inititator mask str\n");
234 		return -ENOMEM;
235 	}
236 
237 	memcpy(imask->mask, mask, len);
238 
239 	/* Replace "ALL" by "ANY" if set */
240 	p = strstr(imask->mask, "ALL");
241 	if (p != NULL) {
242 		SPDK_WARNLOG("Please use \"%s\" instead of \"%s\"\n", "ANY", "ALL");
243 		SPDK_WARNLOG("Converting \"%s\" to \"%s\" automatically\n", "ALL", "ANY");
244 		memcpy(p, "ANY", 3);
245 	}
246 
247 	TAILQ_INSERT_TAIL(&ig->netmask_head, imask, tailq);
248 	ig->nnetmasks++;
249 
250 	SPDK_DEBUGLOG(iscsi, "Netmask %s\n", mask);
251 	return 0;
252 }
253 
254 static int
255 iscsi_init_grp_delete_netmask(struct spdk_iscsi_init_grp *ig, char *mask)
256 {
257 	struct spdk_iscsi_initiator_netmask *imask;
258 
259 	imask = iscsi_init_grp_find_netmask(ig, mask);
260 	if (imask == NULL) {
261 		return -ENOENT;
262 	}
263 
264 	TAILQ_REMOVE(&ig->netmask_head, imask, tailq);
265 	ig->nnetmasks--;
266 	free(imask);
267 	return 0;
268 }
269 
270 static int
271 iscsi_init_grp_add_netmasks(struct spdk_iscsi_init_grp *ig, int num_imasks, char **imasks)
272 {
273 	int i;
274 	int rc;
275 
276 	for (i = 0; i < num_imasks; i++) {
277 		rc = iscsi_init_grp_add_netmask(ig, imasks[i]);
278 		if (rc != 0) {
279 			goto cleanup;
280 		}
281 	}
282 	return 0;
283 
284 cleanup:
285 	for (; i > 0; --i) {
286 		iscsi_init_grp_delete_netmask(ig, imasks[i - 1]);
287 	}
288 	return rc;
289 }
290 
291 static void
292 iscsi_init_grp_delete_all_netmasks(struct spdk_iscsi_init_grp *ig)
293 {
294 	struct spdk_iscsi_initiator_netmask *imask, *tmp;
295 
296 	TAILQ_FOREACH_SAFE(imask, &ig->netmask_head, tailq, tmp) {
297 		TAILQ_REMOVE(&ig->netmask_head, imask, tailq);
298 		ig->nnetmasks--;
299 		free(imask);
300 	}
301 }
302 
303 static int
304 iscsi_init_grp_delete_netmasks(struct spdk_iscsi_init_grp *ig, int num_imasks, char **imasks)
305 {
306 	int i;
307 	int rc;
308 
309 	for (i = 0; i < num_imasks; i++) {
310 		rc = iscsi_init_grp_delete_netmask(ig, imasks[i]);
311 		if (rc != 0) {
312 			goto cleanup;
313 		}
314 	}
315 	return 0;
316 
317 cleanup:
318 	for (; i > 0; --i) {
319 		rc = iscsi_init_grp_add_netmask(ig, imasks[i - 1]);
320 		if (rc != 0) {
321 			iscsi_init_grp_delete_all_netmasks(ig);
322 			break;
323 		}
324 	}
325 	return -1;
326 }
327 
328 int
329 iscsi_init_grp_register(struct spdk_iscsi_init_grp *ig)
330 {
331 	struct spdk_iscsi_init_grp *tmp;
332 	int rc = -1;
333 
334 	assert(ig != NULL);
335 
336 	pthread_mutex_lock(&g_iscsi.mutex);
337 	tmp = iscsi_init_grp_find_by_tag(ig->tag);
338 	if (tmp == NULL) {
339 		TAILQ_INSERT_TAIL(&g_iscsi.ig_head, ig, tailq);
340 		rc = 0;
341 	}
342 	pthread_mutex_unlock(&g_iscsi.mutex);
343 
344 	return rc;
345 }
346 
347 /*
348  * Create initiator group from list of initiator ip/hostnames and netmasks
349  * The initiator hostname/netmask lists are allocated by the caller on the
350  * heap.  Freed later by common initiator_group_destroy() code
351  */
352 int
353 iscsi_init_grp_create_from_initiator_list(int tag,
354 		int num_initiator_names,
355 		char **initiator_names,
356 		int num_initiator_masks,
357 		char **initiator_masks)
358 {
359 	int rc = -1;
360 	struct spdk_iscsi_init_grp *ig = NULL;
361 
362 	SPDK_DEBUGLOG(iscsi,
363 		      "add initiator group (from initiator list) tag=%d, #initiators=%d, #masks=%d\n",
364 		      tag, num_initiator_names, num_initiator_masks);
365 
366 	ig = iscsi_init_grp_create(tag);
367 	if (!ig) {
368 		SPDK_ERRLOG("initiator group create error (%d)\n", tag);
369 		return rc;
370 	}
371 
372 	rc = iscsi_init_grp_add_initiators(ig, num_initiator_names,
373 					   initiator_names);
374 	if (rc < 0) {
375 		SPDK_ERRLOG("add initiator name error\n");
376 		goto cleanup;
377 	}
378 
379 	rc = iscsi_init_grp_add_netmasks(ig, num_initiator_masks,
380 					 initiator_masks);
381 	if (rc < 0) {
382 		SPDK_ERRLOG("add initiator netmask error\n");
383 		goto cleanup;
384 	}
385 
386 	rc = iscsi_init_grp_register(ig);
387 	if (rc < 0) {
388 		SPDK_ERRLOG("initiator group register error (%d)\n", tag);
389 		goto cleanup;
390 	}
391 	return 0;
392 
393 cleanup:
394 	iscsi_init_grp_destroy(ig);
395 	return rc;
396 }
397 
398 int
399 iscsi_init_grp_add_initiators_from_initiator_list(int tag,
400 		int num_initiator_names,
401 		char **initiator_names,
402 		int num_initiator_masks,
403 		char **initiator_masks)
404 {
405 	int rc = -1;
406 	struct spdk_iscsi_init_grp *ig;
407 
408 	SPDK_DEBUGLOG(iscsi,
409 		      "add initiator to initiator group: tag=%d, #initiators=%d, #masks=%d\n",
410 		      tag, num_initiator_names, num_initiator_masks);
411 
412 	pthread_mutex_lock(&g_iscsi.mutex);
413 	ig = iscsi_init_grp_find_by_tag(tag);
414 	if (!ig) {
415 		pthread_mutex_unlock(&g_iscsi.mutex);
416 		SPDK_ERRLOG("initiator group (%d) is not found\n", tag);
417 		return rc;
418 	}
419 
420 	rc = iscsi_init_grp_add_initiators(ig, num_initiator_names,
421 					   initiator_names);
422 	if (rc < 0) {
423 		SPDK_ERRLOG("add initiator name error\n");
424 		goto error;
425 	}
426 
427 	rc = iscsi_init_grp_add_netmasks(ig, num_initiator_masks,
428 					 initiator_masks);
429 	if (rc < 0) {
430 		SPDK_ERRLOG("add initiator netmask error\n");
431 		iscsi_init_grp_delete_initiators(ig, num_initiator_names,
432 						 initiator_names);
433 	}
434 
435 error:
436 	pthread_mutex_unlock(&g_iscsi.mutex);
437 	return rc;
438 }
439 
440 int
441 iscsi_init_grp_delete_initiators_from_initiator_list(int tag,
442 		int num_initiator_names,
443 		char **initiator_names,
444 		int num_initiator_masks,
445 		char **initiator_masks)
446 {
447 	int rc = -1;
448 	struct spdk_iscsi_init_grp *ig;
449 
450 	SPDK_DEBUGLOG(iscsi,
451 		      "delete initiator from initiator group: tag=%d, #initiators=%d, #masks=%d\n",
452 		      tag, num_initiator_names, num_initiator_masks);
453 
454 	pthread_mutex_lock(&g_iscsi.mutex);
455 	ig = iscsi_init_grp_find_by_tag(tag);
456 	if (!ig) {
457 		pthread_mutex_unlock(&g_iscsi.mutex);
458 		SPDK_ERRLOG("initiator group (%d) is not found\n", tag);
459 		return rc;
460 	}
461 
462 	rc = iscsi_init_grp_delete_initiators(ig, num_initiator_names,
463 					      initiator_names);
464 	if (rc < 0) {
465 		SPDK_ERRLOG("delete initiator name error\n");
466 		goto error;
467 	}
468 
469 	rc = iscsi_init_grp_delete_netmasks(ig, num_initiator_masks,
470 					    initiator_masks);
471 	if (rc < 0) {
472 		SPDK_ERRLOG("delete initiator netmask error\n");
473 		iscsi_init_grp_add_initiators(ig, num_initiator_names,
474 					      initiator_names);
475 		goto error;
476 	}
477 
478 error:
479 	pthread_mutex_unlock(&g_iscsi.mutex);
480 	return rc;
481 }
482 
483 void
484 iscsi_init_grp_destroy(struct spdk_iscsi_init_grp *ig)
485 {
486 	if (!ig) {
487 		return;
488 	}
489 
490 	iscsi_init_grp_delete_all_initiators(ig);
491 	iscsi_init_grp_delete_all_netmasks(ig);
492 	free(ig);
493 };
494 
495 struct spdk_iscsi_init_grp *
496 iscsi_init_grp_find_by_tag(int tag)
497 {
498 	struct spdk_iscsi_init_grp *ig;
499 
500 	TAILQ_FOREACH(ig, &g_iscsi.ig_head, tailq) {
501 		if (ig->tag == tag) {
502 			return ig;
503 		}
504 	}
505 
506 	return NULL;
507 }
508 
509 void
510 iscsi_init_grps_destroy(void)
511 {
512 	struct spdk_iscsi_init_grp *ig, *tmp;
513 
514 	SPDK_DEBUGLOG(iscsi, "iscsi_init_grp_array_destroy\n");
515 	pthread_mutex_lock(&g_iscsi.mutex);
516 	TAILQ_FOREACH_SAFE(ig, &g_iscsi.ig_head, tailq, tmp) {
517 		TAILQ_REMOVE(&g_iscsi.ig_head, ig, tailq);
518 		iscsi_init_grp_destroy(ig);
519 	}
520 	pthread_mutex_unlock(&g_iscsi.mutex);
521 }
522 
523 struct spdk_iscsi_init_grp *
524 iscsi_init_grp_unregister(int tag)
525 {
526 	struct spdk_iscsi_init_grp *ig;
527 
528 	pthread_mutex_lock(&g_iscsi.mutex);
529 	TAILQ_FOREACH(ig, &g_iscsi.ig_head, tailq) {
530 		if (ig->tag == tag) {
531 			TAILQ_REMOVE(&g_iscsi.ig_head, ig, tailq);
532 			pthread_mutex_unlock(&g_iscsi.mutex);
533 			return ig;
534 		}
535 	}
536 	pthread_mutex_unlock(&g_iscsi.mutex);
537 	return NULL;
538 }
539 
540 static void
541 iscsi_init_grp_info_json(struct spdk_iscsi_init_grp *ig,
542 			 struct spdk_json_write_ctx *w)
543 {
544 	struct spdk_iscsi_initiator_name *iname;
545 	struct spdk_iscsi_initiator_netmask *imask;
546 
547 	spdk_json_write_object_begin(w);
548 
549 	spdk_json_write_named_int32(w, "tag", ig->tag);
550 
551 	spdk_json_write_named_array_begin(w, "initiators");
552 	TAILQ_FOREACH(iname, &ig->initiator_head, tailq) {
553 		spdk_json_write_string(w, iname->name);
554 	}
555 	spdk_json_write_array_end(w);
556 
557 	spdk_json_write_named_array_begin(w, "netmasks");
558 	TAILQ_FOREACH(imask, &ig->netmask_head, tailq) {
559 		spdk_json_write_string(w, imask->mask);
560 	}
561 	spdk_json_write_array_end(w);
562 
563 	spdk_json_write_object_end(w);
564 }
565 
566 static void
567 iscsi_init_grp_config_json(struct spdk_iscsi_init_grp *ig,
568 			   struct spdk_json_write_ctx *w)
569 {
570 	spdk_json_write_object_begin(w);
571 
572 	spdk_json_write_named_string(w, "method", "iscsi_create_initiator_group");
573 
574 	spdk_json_write_name(w, "params");
575 	iscsi_init_grp_info_json(ig, w);
576 
577 	spdk_json_write_object_end(w);
578 }
579 
580 void
581 iscsi_init_grps_info_json(struct spdk_json_write_ctx *w)
582 {
583 	struct spdk_iscsi_init_grp *ig;
584 
585 	TAILQ_FOREACH(ig, &g_iscsi.ig_head, tailq) {
586 		iscsi_init_grp_info_json(ig, w);
587 	}
588 }
589 
590 void
591 iscsi_init_grps_config_json(struct spdk_json_write_ctx *w)
592 {
593 	struct spdk_iscsi_init_grp *ig;
594 
595 	TAILQ_FOREACH(ig, &g_iscsi.ig_head, tailq) {
596 		iscsi_init_grp_config_json(ig, w);
597 	}
598 }
599