xref: /spdk/lib/iscsi/iscsi_rpc.c (revision 04c48172b9879a8824de83c842087d871c433d12)
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 "iscsi/iscsi.h"
36 #include "iscsi/conn.h"
37 #include "iscsi/tgt_node.h"
38 #include "iscsi/portal_grp.h"
39 #include "iscsi/init_grp.h"
40 
41 #include "spdk/log.h"
42 #include "spdk/rpc.h"
43 
44 extern struct spdk_iscsi_conn *g_conns_array; // TODO: move this to an internal iSCSI header
45 
46 static void
47 spdk_rpc_get_initiator_groups(struct spdk_jsonrpc_server_conn *conn,
48 			      const struct spdk_json_val *params,
49 			      const struct spdk_json_val *id)
50 {
51 	struct spdk_json_write_ctx *w;
52 	struct spdk_iscsi_init_grp *ig;
53 	int i;
54 
55 	if (params != NULL) {
56 		spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
57 						 "get_initiator_groups requires no parameters");
58 		return;
59 	}
60 
61 	if (id == NULL) {
62 		return;
63 	}
64 
65 	w = spdk_jsonrpc_begin_result(conn, id);
66 	spdk_json_write_array_begin(w);
67 
68 	TAILQ_FOREACH(ig, &g_spdk_iscsi.ig_head, tailq) {
69 		spdk_json_write_object_begin(w);
70 
71 		spdk_json_write_name(w, "initiators");
72 		spdk_json_write_array_begin(w);
73 		for (i = 0; i < ig->ninitiators; i++) {
74 			spdk_json_write_string(w, ig->initiators[i]);
75 		}
76 		spdk_json_write_array_end(w);
77 
78 		spdk_json_write_name(w, "tag");
79 		spdk_json_write_int32(w, ig->tag);
80 
81 		spdk_json_write_name(w, "netmasks");
82 		spdk_json_write_array_begin(w);
83 		for (i = 0; i < ig->nnetmasks; i++) {
84 			spdk_json_write_string(w, ig->netmasks[i]);
85 		}
86 		spdk_json_write_array_end(w);
87 
88 		spdk_json_write_object_end(w);
89 	}
90 
91 	spdk_json_write_array_end(w);
92 
93 	spdk_jsonrpc_end_result(conn, w);
94 }
95 SPDK_RPC_REGISTER("get_initiator_groups", spdk_rpc_get_initiator_groups)
96 
97 struct rpc_initiator_list {
98 	size_t num_initiators;
99 	char *initiators[MAX_INITIATOR];
100 };
101 
102 static int
103 decode_rpc_initiator_list(const struct spdk_json_val *val, void *out)
104 {
105 	struct rpc_initiator_list *list = out;
106 
107 	return spdk_json_decode_array(val, spdk_json_decode_string, list->initiators, MAX_INITIATOR,
108 				      &list->num_initiators, sizeof(char *));
109 }
110 
111 static void
112 free_rpc_initiator_list(struct rpc_initiator_list *list)
113 {
114 	size_t i;
115 
116 	for (i = 0; i < list->num_initiators; i++) {
117 		free(list->initiators[i]);
118 	}
119 }
120 
121 struct rpc_netmask_list {
122 	size_t num_netmasks;
123 	char *netmasks[MAX_NETMASK];
124 };
125 
126 static int
127 decode_rpc_netmask_list(const struct spdk_json_val *val, void *out)
128 {
129 	struct rpc_netmask_list *list = out;
130 
131 	return spdk_json_decode_array(val, spdk_json_decode_string, list->netmasks, MAX_NETMASK,
132 				      &list->num_netmasks, sizeof(char *));
133 }
134 
135 static void
136 free_rpc_netmask_list(struct rpc_netmask_list *list)
137 {
138 	size_t i;
139 
140 	for (i = 0; i < list->num_netmasks; i++) {
141 		free(list->netmasks[i]);
142 	}
143 }
144 
145 struct rpc_initiator_group {
146 	int32_t tag;
147 	struct rpc_initiator_list initiator_list;
148 	struct rpc_netmask_list netmask_list;
149 };
150 
151 static void
152 free_rpc_initiator_group(struct rpc_initiator_group *ig)
153 {
154 	free_rpc_initiator_list(&ig->initiator_list);
155 	free_rpc_netmask_list(&ig->netmask_list);
156 }
157 
158 static const struct spdk_json_object_decoder rpc_initiator_group_decoders[] = {
159 	{"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32},
160 	{"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list},
161 	{"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list},
162 };
163 
164 static void
165 spdk_rpc_add_initiator_group(struct spdk_jsonrpc_server_conn *conn,
166 			     const struct spdk_json_val *params,
167 			     const struct spdk_json_val *id)
168 {
169 	struct rpc_initiator_group req = {};
170 	size_t i;
171 	char **initiators = NULL, **netmasks = NULL;
172 	struct spdk_json_write_ctx *w;
173 
174 	if (spdk_json_decode_object(params, rpc_initiator_group_decoders,
175 				    sizeof(rpc_initiator_group_decoders) / sizeof(*rpc_initiator_group_decoders), &req)) {
176 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
177 		goto invalid;
178 	}
179 
180 	if (req.initiator_list.num_initiators == 0 ||
181 	    req.netmask_list.num_netmasks == 0) {
182 		goto invalid;
183 	}
184 
185 	initiators = calloc(req.initiator_list.num_initiators, sizeof(char *));
186 	if (initiators == NULL) {
187 		goto invalid;
188 	}
189 	for (i = 0; i < req.initiator_list.num_initiators; i++) {
190 		initiators[i] = strdup(req.initiator_list.initiators[i]);
191 		if (initiators[i] == NULL) {
192 			goto invalid;
193 		}
194 	}
195 
196 	netmasks = calloc(req.netmask_list.num_netmasks, sizeof(char *));
197 	if (netmasks == NULL) {
198 		goto invalid;
199 	}
200 	for (i = 0; i < req.netmask_list.num_netmasks; i++) {
201 		netmasks[i] = strdup(req.netmask_list.netmasks[i]);
202 		if (netmasks[i] == NULL) {
203 			goto invalid;
204 		}
205 	}
206 
207 	if (spdk_iscsi_init_grp_create_from_initiator_list(req.tag,
208 			req.initiator_list.num_initiators,
209 			initiators,
210 			req.netmask_list.num_netmasks,
211 			netmasks)) {
212 		SPDK_ERRLOG("create_from_initiator_list failed\n");
213 		goto invalid;
214 	}
215 
216 	free_rpc_initiator_group(&req);
217 
218 	if (id == NULL) {
219 		return;
220 	}
221 
222 	w = spdk_jsonrpc_begin_result(conn, id);
223 	spdk_json_write_bool(w, true);
224 	spdk_jsonrpc_end_result(conn, w);
225 	return;
226 
227 invalid:
228 	spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
229 	if (initiators) {
230 		for (i = 0; i < req.initiator_list.num_initiators; i++) {
231 			free(initiators[i]);
232 		}
233 		free(initiators);
234 	}
235 	if (netmasks) {
236 		for (i = 0; i < req.netmask_list.num_netmasks; i++) {
237 			free(netmasks[i]);
238 		}
239 		free(netmasks);
240 	}
241 	free_rpc_initiator_group(&req);
242 }
243 SPDK_RPC_REGISTER("add_initiator_group", spdk_rpc_add_initiator_group)
244 
245 struct rpc_delete_initiator_group {
246 	int32_t tag;
247 };
248 
249 static const struct spdk_json_object_decoder rpc_delete_initiator_group_decoders[] = {
250 	{"tag", offsetof(struct rpc_delete_initiator_group, tag), spdk_json_decode_int32},
251 };
252 
253 static void
254 spdk_rpc_delete_initiator_group(struct spdk_jsonrpc_server_conn *conn,
255 				const struct spdk_json_val *params,
256 				const struct spdk_json_val *id)
257 {
258 	struct rpc_delete_initiator_group req = {};
259 	struct spdk_json_write_ctx *w;
260 	struct spdk_iscsi_init_grp *ig;
261 
262 	if (spdk_json_decode_object(params, rpc_delete_initiator_group_decoders,
263 				    sizeof(rpc_delete_initiator_group_decoders) / sizeof(*rpc_delete_initiator_group_decoders),
264 				    &req)) {
265 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
266 		goto invalid;
267 	}
268 
269 	if (spdk_iscsi_init_grp_deletable(req.tag)) {
270 		goto invalid;
271 	}
272 
273 	ig = spdk_iscsi_init_grp_find_by_tag(req.tag);
274 	if (!ig) {
275 		goto invalid;
276 	}
277 	spdk_iscsi_tgt_node_delete_map(NULL, ig);
278 	spdk_iscsi_init_grp_release(ig);
279 
280 	if (id == NULL) {
281 		return;
282 	}
283 
284 	w = spdk_jsonrpc_begin_result(conn, id);
285 	spdk_json_write_bool(w, true);
286 	spdk_jsonrpc_end_result(conn, w);
287 	return;
288 
289 invalid:
290 	spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
291 }
292 SPDK_RPC_REGISTER("delete_initiator_group", spdk_rpc_delete_initiator_group)
293 
294 static void
295 spdk_rpc_get_target_nodes(struct spdk_jsonrpc_server_conn *conn,
296 			  const struct spdk_json_val *params,
297 			  const struct spdk_json_val *id)
298 {
299 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
300 	struct spdk_json_write_ctx *w;
301 	size_t tgt_idx;
302 	int i;
303 
304 	if (params != NULL) {
305 		spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
306 						 "get_target_nodes requires no parameters");
307 		return;
308 	}
309 
310 	if (id == NULL) {
311 		return;
312 	}
313 
314 	w = spdk_jsonrpc_begin_result(conn, id);
315 	spdk_json_write_array_begin(w);
316 
317 	for (tgt_idx = 0 ; tgt_idx < MAX_ISCSI_TARGET_NODE; tgt_idx++) {
318 		struct spdk_iscsi_tgt_node *tgtnode = iscsi->target[tgt_idx];
319 
320 		if (tgtnode == NULL) {
321 			continue;
322 		}
323 
324 		spdk_json_write_object_begin(w);
325 
326 		spdk_json_write_name(w, "name");
327 		spdk_json_write_string(w, tgtnode->name);
328 
329 		if (tgtnode->alias) {
330 			spdk_json_write_name(w, "alias_name");
331 			spdk_json_write_string(w, tgtnode->alias);
332 		}
333 
334 		spdk_json_write_name(w, "pg_ig_maps");
335 		spdk_json_write_array_begin(w);
336 		for (i = 0; i < tgtnode->maxmap; i++) {
337 			spdk_json_write_object_begin(w);
338 			spdk_json_write_name(w, "pg_tag");
339 			spdk_json_write_int32(w, tgtnode->map[i].pg->tag);
340 			spdk_json_write_name(w, "ig_tag");
341 			spdk_json_write_int32(w, tgtnode->map[i].ig->tag);
342 			spdk_json_write_object_end(w);
343 		}
344 		spdk_json_write_array_end(w);
345 
346 		spdk_json_write_name(w, "luns");
347 		spdk_json_write_array_begin(w);
348 		for (i = 0; i < tgtnode->dev->maxlun; i++) {
349 			if (tgtnode->dev->lun[i]) {
350 				spdk_json_write_object_begin(w);
351 				spdk_json_write_name(w, "name");
352 				spdk_json_write_string(w, tgtnode->dev->lun[i]->name);
353 				spdk_json_write_name(w, "id");
354 				spdk_json_write_int32(w, tgtnode->dev->lun[i]->id);
355 				spdk_json_write_object_end(w);
356 			}
357 		}
358 		spdk_json_write_array_end(w);
359 
360 		spdk_json_write_name(w, "queue_depth");
361 		spdk_json_write_int32(w, tgtnode->queue_depth);
362 
363 		/*
364 		 * TODO: convert these to bool
365 		 */
366 
367 		spdk_json_write_name(w, "chap_disabled");
368 		spdk_json_write_int32(w, tgtnode->auth_chap_disabled);
369 
370 		spdk_json_write_name(w, "chap_required");
371 		spdk_json_write_int32(w, tgtnode->auth_chap_required);
372 
373 		spdk_json_write_name(w, "chap_mutual");
374 		spdk_json_write_int32(w, tgtnode->auth_chap_mutual);
375 
376 		spdk_json_write_name(w, "chap_auth_group");
377 		spdk_json_write_int32(w, tgtnode->auth_group);
378 
379 		spdk_json_write_object_end(w);
380 	}
381 	spdk_json_write_array_end(w);
382 
383 	spdk_jsonrpc_end_result(conn, w);
384 }
385 SPDK_RPC_REGISTER("get_target_nodes", spdk_rpc_get_target_nodes)
386 
387 struct rpc_pg_tags {
388 	size_t num_tags;
389 	int32_t tags[MAX_TARGET_MAP];
390 };
391 
392 static int
393 decode_rpc_pg_tags(const struct spdk_json_val *val, void *out)
394 {
395 	struct rpc_pg_tags *pg_tags = out;
396 
397 	return spdk_json_decode_array(val, spdk_json_decode_int32, pg_tags->tags, MAX_TARGET_MAP,
398 				      &pg_tags->num_tags, sizeof(int32_t));
399 }
400 
401 struct rpc_ig_tags {
402 	size_t num_tags;
403 	int32_t tags[MAX_TARGET_MAP];
404 };
405 
406 static int
407 decode_rpc_ig_tags(const struct spdk_json_val *val, void *out)
408 {
409 	struct rpc_ig_tags *ig_tags = out;
410 
411 	return spdk_json_decode_array(val, spdk_json_decode_int32, ig_tags->tags, MAX_TARGET_MAP,
412 				      &ig_tags->num_tags, sizeof(int32_t));
413 }
414 
415 #define RPC_CONSTRUCT_TARGET_NODE_MAX_LUN	64
416 
417 struct rpc_lun_names {
418 	size_t num_names;
419 	char *names[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN];
420 };
421 
422 static int
423 decode_rpc_lun_names(const struct spdk_json_val *val, void *out)
424 {
425 	struct rpc_lun_names *lun_names = out;
426 
427 	return spdk_json_decode_array(val, spdk_json_decode_string, lun_names->names,
428 				      RPC_CONSTRUCT_TARGET_NODE_MAX_LUN,
429 				      &lun_names->num_names, sizeof(char *));
430 }
431 
432 static void
433 free_rpc_lun_names(struct rpc_lun_names *r)
434 {
435 	size_t i;
436 
437 	for (i = 0; i < r->num_names; i++) {
438 		free(r->names[i]);
439 	}
440 }
441 
442 struct rpc_lun_ids {
443 	size_t num_ids;
444 	int32_t ids[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN];
445 };
446 
447 static int
448 decode_rpc_lun_ids(const struct spdk_json_val *val, void *out)
449 {
450 	struct rpc_lun_ids *lun_ids = out;
451 
452 	return spdk_json_decode_array(val, spdk_json_decode_int32, lun_ids->ids,
453 				      RPC_CONSTRUCT_TARGET_NODE_MAX_LUN,
454 				      &lun_ids->num_ids, sizeof(int32_t));
455 }
456 
457 struct rpc_target_node {
458 	char *name;
459 	char *alias_name;
460 
461 	struct rpc_pg_tags pg_tags;
462 	struct rpc_ig_tags ig_tags;
463 
464 	struct rpc_lun_names lun_names;
465 	struct rpc_lun_ids lun_ids;
466 
467 	int32_t queue_depth;
468 	int32_t chap_disabled;
469 	int32_t chap_required;
470 	int32_t chap_mutual;
471 	int32_t chap_auth_group;
472 };
473 
474 static void
475 free_rpc_target_node(struct rpc_target_node *req)
476 {
477 	free_rpc_lun_names(&req->lun_names);
478 }
479 
480 static const struct spdk_json_object_decoder rpc_target_node_decoders[] = {
481 	{"name", offsetof(struct rpc_target_node, name), spdk_json_decode_string},
482 	{"alias_name", offsetof(struct rpc_target_node, alias_name), spdk_json_decode_string},
483 	{"pg_tags", offsetof(struct rpc_target_node, pg_tags), decode_rpc_pg_tags},
484 	{"ig_tags", offsetof(struct rpc_target_node, ig_tags), decode_rpc_ig_tags},
485 	{"lun_names", offsetof(struct rpc_target_node, lun_names), decode_rpc_lun_names},
486 	{"lun_ids", offsetof(struct rpc_target_node, lun_ids), decode_rpc_lun_ids},
487 	{"queue_depth", offsetof(struct rpc_target_node, queue_depth), spdk_json_decode_int32},
488 	{"chap_disabled", offsetof(struct rpc_target_node, chap_disabled), spdk_json_decode_int32},
489 	{"chap_required", offsetof(struct rpc_target_node, chap_required), spdk_json_decode_int32},
490 	{"chap_mutual", offsetof(struct rpc_target_node, chap_mutual), spdk_json_decode_int32},
491 	{"chap_auth_group", offsetof(struct rpc_target_node, chap_auth_group), spdk_json_decode_int32},
492 };
493 
494 static void
495 spdk_rpc_construct_target_node(struct spdk_jsonrpc_server_conn *conn,
496 			       const struct spdk_json_val *params,
497 			       const struct spdk_json_val *id)
498 {
499 	struct rpc_target_node req = {};
500 	struct spdk_json_write_ctx *w;
501 	struct spdk_iscsi_tgt_node *target;
502 
503 	if (spdk_json_decode_object(params, rpc_target_node_decoders,
504 				    sizeof(rpc_target_node_decoders) / sizeof(*rpc_target_node_decoders),
505 				    &req)) {
506 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
507 		goto invalid;
508 	}
509 
510 	if (req.pg_tags.num_tags != req.ig_tags.num_tags) {
511 		SPDK_ERRLOG("pg_tags/ig_tags count mismatch\n");
512 		goto invalid;
513 	}
514 
515 	if (req.lun_names.num_names != req.lun_ids.num_ids) {
516 		SPDK_ERRLOG("lun_names/lun_ids count mismatch\n");
517 		goto invalid;
518 	}
519 
520 	/*
521 	 * Use default parameters in a few places:
522 	 *  index = -1 : automatically pick an index for the new target node
523 	 *  alias = NULL
524 	 *  0, 0 = disable header/data digests
525 	 */
526 	target = spdk_iscsi_tgt_node_construct(-1, req.name, req.alias_name,
527 					       req.pg_tags.tags,
528 					       req.ig_tags.tags,
529 					       req.pg_tags.num_tags,
530 					       req.lun_names.names,
531 					       req.lun_ids.ids,
532 					       req.lun_names.num_names,
533 					       req.queue_depth,
534 					       req.chap_disabled,
535 					       req.chap_required,
536 					       req.chap_mutual,
537 					       req.chap_auth_group,
538 					       0, 0);
539 
540 	if (target == NULL) {
541 		goto invalid;
542 	}
543 
544 	free_rpc_target_node(&req);
545 
546 	if (id == NULL) {
547 		return;
548 	}
549 
550 	w = spdk_jsonrpc_begin_result(conn, id);
551 	spdk_json_write_bool(w, true);
552 	spdk_jsonrpc_end_result(conn, w);
553 	return;
554 
555 invalid:
556 	spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
557 	free_rpc_target_node(&req);
558 }
559 SPDK_RPC_REGISTER("construct_target_node", spdk_rpc_construct_target_node)
560 
561 struct rpc_delete_target_node {
562 	char *name;
563 };
564 
565 static void
566 free_rpc_delete_target_node(struct rpc_delete_target_node *r)
567 {
568 	free(r->name);
569 }
570 
571 static const struct spdk_json_object_decoder rpc_delete_target_node_decoders[] = {
572 	{"name", offsetof(struct rpc_delete_target_node, name), spdk_json_decode_string},
573 };
574 
575 static void
576 spdk_rpc_delete_target_node(struct spdk_jsonrpc_server_conn *conn,
577 			    const struct spdk_json_val *params,
578 			    const struct spdk_json_val *id)
579 {
580 	struct rpc_delete_target_node req = {};
581 	struct spdk_json_write_ctx *w;
582 
583 	if (spdk_json_decode_object(params, rpc_delete_target_node_decoders,
584 				    sizeof(rpc_delete_target_node_decoders) / sizeof(*rpc_delete_target_node_decoders),
585 				    &req)) {
586 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
587 		goto invalid;
588 	}
589 
590 	if (req.name == NULL) {
591 		SPDK_ERRLOG("missing name param\n");
592 		goto invalid;
593 	}
594 
595 	if (spdk_iscsi_shutdown_tgt_node_by_name(req.name)) {
596 		SPDK_ERRLOG("shutdown_tgt_node_by_name failed\n");
597 		goto invalid;
598 	}
599 
600 	free_rpc_delete_target_node(&req);
601 
602 	if (id == NULL) {
603 		return;
604 	}
605 
606 	w = spdk_jsonrpc_begin_result(conn, id);
607 	spdk_json_write_bool(w, true);
608 	spdk_jsonrpc_end_result(conn, w);
609 	return;
610 
611 invalid:
612 	spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
613 	free_rpc_delete_target_node(&req);
614 }
615 SPDK_RPC_REGISTER("delete_target_node", spdk_rpc_delete_target_node)
616 
617 static void
618 spdk_rpc_get_portal_groups(struct spdk_jsonrpc_server_conn *conn,
619 			   const struct spdk_json_val *params,
620 			   const struct spdk_json_val *id)
621 {
622 	struct spdk_json_write_ctx *w;
623 	struct spdk_iscsi_portal_grp *pg;
624 	struct spdk_iscsi_portal *portal;
625 
626 	if (params != NULL) {
627 		spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
628 						 "get_portal_groups requires no parameters");
629 		return;
630 	}
631 
632 	if (id == NULL) {
633 		return;
634 	}
635 
636 	w = spdk_jsonrpc_begin_result(conn, id);
637 	spdk_json_write_array_begin(w);
638 
639 	TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
640 		spdk_json_write_object_begin(w);
641 
642 		spdk_json_write_name(w, "portals");
643 		spdk_json_write_array_begin(w);
644 		TAILQ_FOREACH(portal, &pg->head, tailq) {
645 			spdk_json_write_object_begin(w);
646 			spdk_json_write_name(w, "host");
647 			spdk_json_write_string(w, portal->host);
648 			spdk_json_write_name(w, "port");
649 			spdk_json_write_string(w, portal->port);
650 			spdk_json_write_object_end(w);
651 		}
652 		spdk_json_write_array_end(w);
653 
654 		spdk_json_write_name(w, "tag");
655 		spdk_json_write_int32(w, pg->tag);
656 
657 		spdk_json_write_object_end(w);
658 	}
659 
660 	spdk_json_write_array_end(w);
661 
662 	spdk_jsonrpc_end_result(conn, w);
663 }
664 SPDK_RPC_REGISTER("get_portal_groups", spdk_rpc_get_portal_groups)
665 
666 struct rpc_portal {
667 	char *host;
668 	char *port;
669 };
670 
671 struct rpc_portal_list {
672 	size_t num_portals;
673 	struct rpc_portal portals[MAX_PORTAL];
674 };
675 
676 struct rpc_portal_group {
677 	int32_t tag;
678 	struct rpc_portal_list portal_list;
679 };
680 
681 static void
682 free_rpc_portal(struct rpc_portal *portal)
683 {
684 	free(portal->host);
685 	portal->host = NULL;
686 	free(portal->port);
687 	portal->port = NULL;
688 }
689 
690 static void
691 free_rpc_portal_list(struct rpc_portal_list *pl)
692 {
693 	size_t i;
694 
695 	for (i = 0; i < pl->num_portals; i++) {
696 		free_rpc_portal(&pl->portals[i]);
697 	}
698 	pl->num_portals = 0;
699 }
700 
701 static void
702 free_rpc_portal_group(struct rpc_portal_group *pg)
703 {
704 	free_rpc_portal_list(&pg->portal_list);
705 }
706 
707 static const struct spdk_json_object_decoder rpc_portal_decoders[] = {
708 	{"host", offsetof(struct rpc_portal, host), spdk_json_decode_string},
709 	{"port", offsetof(struct rpc_portal, port), spdk_json_decode_string},
710 };
711 
712 static int
713 decode_rpc_portal(const struct spdk_json_val *val, void *out)
714 {
715 	struct rpc_portal *portal = out;
716 
717 	return spdk_json_decode_object(val, rpc_portal_decoders,
718 				       sizeof(rpc_portal_decoders) / sizeof(*rpc_portal_decoders),
719 				       portal);
720 }
721 
722 static int
723 decode_rpc_portal_list(const struct spdk_json_val *val, void *out)
724 {
725 	struct rpc_portal_list *list = out;
726 
727 	return spdk_json_decode_array(val, decode_rpc_portal, list->portals, MAX_PORTAL, &list->num_portals,
728 				      sizeof(struct rpc_portal));
729 }
730 
731 static const struct spdk_json_object_decoder rpc_portal_group_decoders[] = {
732 	{"tag", offsetof(struct rpc_portal_group, tag), spdk_json_decode_int32},
733 	{"portals", offsetof(struct rpc_portal_group, portal_list), decode_rpc_portal_list},
734 };
735 
736 static void
737 spdk_rpc_add_portal_group(struct spdk_jsonrpc_server_conn *conn,
738 			  const struct spdk_json_val *params,
739 			  const struct spdk_json_val *id)
740 {
741 	struct rpc_portal_group req = {};
742 	struct spdk_iscsi_portal *portal_list[MAX_PORTAL] = {};
743 	struct spdk_json_write_ctx *w;
744 	size_t i;
745 
746 	if (spdk_json_decode_object(params, rpc_portal_group_decoders,
747 				    sizeof(rpc_portal_group_decoders) / sizeof(*rpc_portal_group_decoders),
748 				    &req)) {
749 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
750 		goto invalid;
751 	}
752 
753 	for (i = 0; i < req.portal_list.num_portals; i++) {
754 		portal_list[i] = spdk_iscsi_portal_create(req.portal_list.portals[i].host,
755 				 req.portal_list.portals[i].port, 0);
756 		if (portal_list[i] == NULL) {
757 			SPDK_ERRLOG("portal_list allocation failed\n");
758 			goto invalid;
759 		}
760 	}
761 
762 	if (spdk_iscsi_portal_grp_create_from_portal_list(req.tag, portal_list,
763 			req.portal_list.num_portals)) {
764 		SPDK_ERRLOG("create_from_portal_list failed\n");
765 		goto invalid;
766 	}
767 
768 	/*
769 	 * Leave the host and port strings allocated here and don't call free_rpc_portal_group(),
770 	 *  because the pointers are inserted directly into the portal group list.
771 	 */
772 
773 	if (id == NULL) {
774 		return;
775 	}
776 
777 	w = spdk_jsonrpc_begin_result(conn, id);
778 	spdk_json_write_bool(w, true);
779 	spdk_jsonrpc_end_result(conn, w);
780 	return;
781 
782 invalid:
783 	spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
784 	for (i = 0; i < req.portal_list.num_portals; i++) {
785 		spdk_iscsi_portal_destroy(portal_list[i]);
786 	}
787 	free_rpc_portal_group(&req);
788 }
789 SPDK_RPC_REGISTER("add_portal_group", spdk_rpc_add_portal_group)
790 
791 struct rpc_delete_portal_group {
792 	int32_t tag;
793 };
794 
795 static const struct spdk_json_object_decoder rpc_delete_portal_group_decoders[] = {
796 	{"tag", offsetof(struct rpc_delete_portal_group, tag), spdk_json_decode_int32},
797 };
798 
799 static void
800 spdk_rpc_delete_portal_group(struct spdk_jsonrpc_server_conn *conn,
801 			     const struct spdk_json_val *params,
802 			     const struct spdk_json_val *id)
803 {
804 	struct rpc_delete_portal_group req = {};
805 	struct spdk_json_write_ctx *w;
806 	struct spdk_iscsi_portal_grp *pg;
807 
808 	if (spdk_json_decode_object(params, rpc_delete_portal_group_decoders,
809 				    sizeof(rpc_delete_portal_group_decoders) / sizeof(*rpc_delete_portal_group_decoders),
810 				    &req)) {
811 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
812 		goto invalid;
813 	}
814 
815 	if (spdk_iscsi_portal_grp_deletable(req.tag)) {
816 		goto invalid;
817 	}
818 
819 	pg = spdk_iscsi_portal_grp_find_by_tag(req.tag);
820 	if (!pg) {
821 		goto invalid;
822 	}
823 
824 	spdk_iscsi_tgt_node_delete_map(pg, NULL);
825 	spdk_iscsi_portal_grp_release(pg);
826 
827 	if (id == NULL) {
828 		return;
829 	}
830 
831 	w = spdk_jsonrpc_begin_result(conn, id);
832 	spdk_json_write_bool(w, true);
833 	spdk_jsonrpc_end_result(conn, w);
834 	return;
835 
836 invalid:
837 	spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
838 }
839 SPDK_RPC_REGISTER("delete_portal_group", spdk_rpc_delete_portal_group)
840 
841 static void
842 spdk_rpc_get_iscsi_connections(struct spdk_jsonrpc_server_conn *conn,
843 			       const struct spdk_json_val *params,
844 			       const struct spdk_json_val *id)
845 {
846 	struct spdk_json_write_ctx *w;
847 	struct spdk_iscsi_conn *conns = g_conns_array;
848 	int i;
849 	uint16_t tsih;
850 
851 	if (params != NULL) {
852 		spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
853 						 "get_iscsi_connections requires no parameters");
854 		return;
855 	}
856 
857 	if (id == NULL) {
858 		return;
859 	}
860 
861 	w = spdk_jsonrpc_begin_result(conn, id);
862 	spdk_json_write_array_begin(w);
863 
864 	for (i = 0; i < MAX_ISCSI_CONNECTIONS; i++) {
865 		struct spdk_iscsi_conn *c = &conns[i];
866 
867 		if (!c->is_valid) {
868 			continue;
869 		}
870 
871 		spdk_json_write_object_begin(w);
872 
873 		spdk_json_write_name(w, "id");
874 		spdk_json_write_int32(w, c->id);
875 
876 		spdk_json_write_name(w, "cid");
877 		spdk_json_write_int32(w, c->cid);
878 
879 		/*
880 		 * If we try to return data for a connection that has not
881 		 *  logged in yet, the session will not be set.  So in this
882 		 *  case, return -1 for the tsih rather than segfaulting
883 		 *  on the null c->sess.
884 		 */
885 		if (c->sess == NULL) {
886 			tsih = -1;
887 		} else {
888 			tsih = c->sess->tsih;
889 		}
890 		spdk_json_write_name(w, "tsih");
891 		spdk_json_write_int32(w, tsih);
892 
893 		spdk_json_write_name(w, "is_idle");
894 		spdk_json_write_int32(w, c->is_idle);
895 
896 		spdk_json_write_name(w, "lcore_id");
897 		spdk_json_write_int32(w, c->lcore);
898 
899 		spdk_json_write_name(w, "initiator_addr");
900 		spdk_json_write_string(w, c->initiator_addr);
901 
902 		spdk_json_write_name(w, "target_addr");
903 		spdk_json_write_string(w, c->target_addr);
904 
905 		spdk_json_write_name(w, "target_node_name");
906 		spdk_json_write_string(w, c->target_short_name);
907 
908 		spdk_json_write_object_end(w);
909 	}
910 	spdk_json_write_array_end(w);
911 
912 	spdk_jsonrpc_end_result(conn, w);
913 }
914 SPDK_RPC_REGISTER("get_iscsi_connections", spdk_rpc_get_iscsi_connections)
915