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