xref: /spdk/lib/vhost/vhost_rpc.c (revision eb8b1e20a9c8a6bc79f32fde8693d2791a74c34d)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk_internal/log.h"
37 #include "spdk/rpc.h"
38 #include "spdk/util.h"
39 #include "spdk/string.h"
40 #include "spdk/env.h"
41 
42 #include "spdk/scsi.h"
43 #include "spdk/vhost.h"
44 #include "vhost_internal.h"
45 #include "spdk/bdev.h"
46 
47 struct rpc_vhost_scsi_ctrlr {
48 	char *ctrlr;
49 	char *cpumask;
50 };
51 
52 static void
53 free_rpc_vhost_scsi_ctrlr(struct rpc_vhost_scsi_ctrlr *req)
54 {
55 	free(req->ctrlr);
56 	free(req->cpumask);
57 }
58 
59 static const struct spdk_json_object_decoder rpc_construct_vhost_ctrlr[] = {
60 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
61 	{"cpumask", offsetof(struct rpc_vhost_scsi_ctrlr, cpumask), spdk_json_decode_string, true},
62 };
63 
64 static void
65 spdk_rpc_construct_vhost_scsi_controller(struct spdk_jsonrpc_request *request,
66 		const struct spdk_json_val *params)
67 {
68 	struct rpc_vhost_scsi_ctrlr req = {0};
69 	struct spdk_json_write_ctx *w;
70 	int rc;
71 	char buf[64];
72 
73 	if (spdk_json_decode_object(params, rpc_construct_vhost_ctrlr,
74 				    SPDK_COUNTOF(rpc_construct_vhost_ctrlr),
75 				    &req)) {
76 		SPDK_DEBUGLOG(SPDK_TRACE_VHOST_RPC, "spdk_json_decode_object failed\n");
77 		rc = -EINVAL;
78 		goto invalid;
79 	}
80 
81 	rc = spdk_vhost_scsi_dev_construct(req.ctrlr, req.cpumask);
82 	if (rc < 0) {
83 		goto invalid;
84 	}
85 
86 	free_rpc_vhost_scsi_ctrlr(&req);
87 
88 	w = spdk_jsonrpc_begin_result(request);
89 	if (w == NULL) {
90 		return;
91 	}
92 
93 	spdk_json_write_bool(w, true);
94 	spdk_jsonrpc_end_result(request, w);
95 	return;
96 
97 invalid:
98 	spdk_strerror_r(-rc, buf, sizeof(buf));
99 	free_rpc_vhost_scsi_ctrlr(&req);
100 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
101 }
102 SPDK_RPC_REGISTER("construct_vhost_scsi_controller", spdk_rpc_construct_vhost_scsi_controller)
103 
104 struct rpc_add_vhost_scsi_ctrlr_lun {
105 	char *ctrlr;
106 	uint32_t scsi_dev_num;
107 	char *lun_name;
108 
109 	struct spdk_jsonrpc_request *request;
110 };
111 
112 static void
113 free_rpc_add_vhost_scsi_ctrlr_lun(struct rpc_add_vhost_scsi_ctrlr_lun *req)
114 {
115 	free(req->ctrlr);
116 	free(req->lun_name);
117 	free(req);
118 }
119 
120 static const struct spdk_json_object_decoder rpc_vhost_add_lun[] = {
121 	{"ctrlr", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, ctrlr), spdk_json_decode_string },
122 	{"scsi_dev_num", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, scsi_dev_num), spdk_json_decode_uint32},
123 	{"lun_name", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, lun_name), spdk_json_decode_string },
124 };
125 
126 static int
127 spdk_rpc_add_vhost_scsi_lun_cb(struct spdk_vhost_dev *vdev, void *arg)
128 {
129 	struct rpc_add_vhost_scsi_ctrlr_lun *rpc = arg;
130 	struct spdk_jsonrpc_request *request = rpc->request;
131 	struct spdk_json_write_ctx *w;
132 	int rc;
133 	char buf[64];
134 
135 	if (vdev == NULL) {
136 		rc = -ENODEV;
137 		goto invalid;
138 	}
139 
140 	rc = spdk_vhost_scsi_dev_add_dev(vdev, rpc->scsi_dev_num, rpc->lun_name);
141 	if (rc < 0) {
142 		goto invalid;
143 	}
144 
145 	free_rpc_add_vhost_scsi_ctrlr_lun(rpc);
146 
147 	w = spdk_jsonrpc_begin_result(request);
148 	if (w == NULL) {
149 		return -1;
150 	}
151 
152 	spdk_json_write_bool(w, true);
153 	spdk_jsonrpc_end_result(request, w);
154 	return 0;
155 
156 invalid:
157 	free_rpc_add_vhost_scsi_ctrlr_lun(rpc);
158 	spdk_strerror_r(-rc, buf, sizeof(buf));
159 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
160 	return rc;
161 }
162 
163 static void
164 spdk_rpc_add_vhost_scsi_lun(struct spdk_jsonrpc_request *request,
165 			    const struct spdk_json_val *params)
166 {
167 	struct rpc_add_vhost_scsi_ctrlr_lun *req;
168 	char buf[64];
169 	int rc;
170 
171 	req = calloc(1, sizeof(*req));
172 	if (req == NULL) {
173 		rc = -ENOMEM;
174 		goto invalid;
175 	}
176 
177 	req->request = request;
178 	if (spdk_json_decode_object(params, rpc_vhost_add_lun,
179 				    SPDK_COUNTOF(rpc_vhost_add_lun),
180 				    req)) {
181 		SPDK_DEBUGLOG(SPDK_TRACE_VHOST_RPC, "spdk_json_decode_object failed\n");
182 		rc = -EINVAL;
183 		goto invalid;
184 	}
185 
186 	if (req->ctrlr == NULL) {
187 		SPDK_ERRLOG("No controller name\n");
188 		rc = -EINVAL;
189 		goto invalid;
190 	}
191 
192 	spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_add_vhost_scsi_lun_cb, req);
193 
194 	return;
195 
196 invalid:
197 	if (req) {
198 		free_rpc_add_vhost_scsi_ctrlr_lun(req);
199 	}
200 	spdk_strerror_r(-rc, buf, sizeof(buf));
201 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
202 }
203 SPDK_RPC_REGISTER("add_vhost_scsi_lun", spdk_rpc_add_vhost_scsi_lun)
204 
205 struct rpc_remove_vhost_scsi_ctrlr_dev {
206 	char *ctrlr;
207 	uint32_t scsi_dev_num;
208 
209 	struct spdk_jsonrpc_request *request;
210 };
211 
212 static void
213 free_rpc_remove_vhost_scsi_ctrlr_dev(struct rpc_remove_vhost_scsi_ctrlr_dev *req)
214 {
215 	free(req->ctrlr);
216 	free(req);
217 }
218 
219 static const struct spdk_json_object_decoder rpc_vhost_remove_dev[] = {
220 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, ctrlr), spdk_json_decode_string },
221 	{"scsi_dev_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, scsi_dev_num), spdk_json_decode_uint32},
222 };
223 
224 static int
225 spdk_rpc_remove_vhost_scsi_dev_finish_cb(struct spdk_vhost_dev *vdev, void *arg)
226 {
227 	struct rpc_remove_vhost_scsi_ctrlr_dev *rpc = arg;
228 	struct spdk_jsonrpc_request *request = rpc->request;
229 	struct spdk_json_write_ctx *w;
230 
231 	free_rpc_remove_vhost_scsi_ctrlr_dev(rpc);
232 
233 	w = spdk_jsonrpc_begin_result(request);
234 	if (w == NULL) {
235 		return -1;
236 	}
237 
238 	spdk_json_write_bool(w, true);
239 	spdk_jsonrpc_end_result(request, w);
240 	return 0;
241 }
242 
243 static int
244 spdk_rpc_remove_vhost_scsi_dev_cb(struct spdk_vhost_dev *vdev, void *arg)
245 {
246 	struct rpc_remove_vhost_scsi_ctrlr_dev *rpc = arg;
247 	struct spdk_jsonrpc_request *request = rpc->request;
248 	char buf[64];
249 	int rc;
250 
251 	if (vdev == NULL) {
252 		rc = -ENODEV;
253 		goto invalid;
254 	}
255 
256 	rc = spdk_vhost_scsi_dev_remove_dev(vdev, rpc->scsi_dev_num,
257 					    spdk_rpc_remove_vhost_scsi_dev_finish_cb, rpc);
258 	if (rc < 0) {
259 		goto invalid;
260 	}
261 
262 	return 0;
263 
264 invalid:
265 	free_rpc_remove_vhost_scsi_ctrlr_dev(rpc);
266 	spdk_strerror_r(-rc, buf, sizeof(buf));
267 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
268 	return rc;
269 }
270 
271 static void
272 spdk_rpc_remove_vhost_scsi_dev(struct spdk_jsonrpc_request *request,
273 			       const struct spdk_json_val *params)
274 {
275 	struct rpc_remove_vhost_scsi_ctrlr_dev *req;
276 	int rc;
277 	char buf[64];
278 
279 	req = calloc(1, sizeof(*req));
280 	if (req == NULL) {
281 		rc = -ENOMEM;
282 		goto invalid;
283 	}
284 
285 	req->request = request;
286 	if (spdk_json_decode_object(params, rpc_vhost_remove_dev,
287 				    SPDK_COUNTOF(rpc_vhost_remove_dev),
288 				    req)) {
289 		SPDK_DEBUGLOG(SPDK_TRACE_VHOST_RPC, "spdk_json_decode_object failed\n");
290 		rc = -EINVAL;
291 		goto invalid;
292 	}
293 
294 	spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_remove_vhost_scsi_dev_cb, req);
295 
296 	return;
297 
298 invalid:
299 	if (req) {
300 		free_rpc_remove_vhost_scsi_ctrlr_dev(req);
301 	}
302 	spdk_strerror_r(-rc, buf, sizeof(buf));
303 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
304 }
305 
306 SPDK_RPC_REGISTER("remove_vhost_scsi_dev", spdk_rpc_remove_vhost_scsi_dev)
307 
308 struct rpc_vhost_blk_ctrlr {
309 	char *ctrlr;
310 	char *dev_name;
311 	char *cpumask;
312 	bool readonly;
313 };
314 
315 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
316 	{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
317 	{"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string },
318 	{"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true},
319 	{"readonly", offsetof(struct rpc_vhost_blk_ctrlr, readonly), spdk_json_decode_bool, true},
320 };
321 
322 static void
323 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
324 {
325 	free(req->ctrlr);
326 	free(req->dev_name);
327 	free(req->cpumask);
328 }
329 
330 static void
331 spdk_rpc_construct_vhost_blk_controller(struct spdk_jsonrpc_request *request,
332 					const struct spdk_json_val *params)
333 {
334 	struct rpc_vhost_blk_ctrlr req = {0};
335 	struct spdk_json_write_ctx *w;
336 	int rc;
337 	char buf[64];
338 
339 	if (spdk_json_decode_object(params, rpc_construct_vhost_blk_ctrlr,
340 				    SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr),
341 				    &req)) {
342 		SPDK_DEBUGLOG(SPDK_TRACE_VHOST_RPC, "spdk_json_decode_object failed\n");
343 		rc = -EINVAL;
344 		goto invalid;
345 	}
346 
347 	rc = spdk_vhost_blk_construct(req.ctrlr, req.cpumask, req.dev_name, req.readonly);
348 	if (rc < 0) {
349 		goto invalid;
350 	}
351 
352 	free_rpc_vhost_blk_ctrlr(&req);
353 
354 	w = spdk_jsonrpc_begin_result(request);
355 	if (w == NULL) {
356 		return;
357 	}
358 
359 	spdk_json_write_bool(w, true);
360 	spdk_jsonrpc_end_result(request, w);
361 	return;
362 
363 invalid:
364 	spdk_strerror_r(-rc, buf, sizeof(buf));
365 	free_rpc_vhost_blk_ctrlr(&req);
366 	spdk_jsonrpc_send_error_response(request,
367 					 SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
368 
369 }
370 SPDK_RPC_REGISTER("construct_vhost_blk_controller", spdk_rpc_construct_vhost_blk_controller)
371 
372 struct rpc_remove_vhost_ctrlr {
373 	char *ctrlr;
374 
375 	struct spdk_jsonrpc_request *request;
376 };
377 
378 static const struct spdk_json_object_decoder rpc_remove_vhost_ctrlr[] = {
379 	{"ctrlr", offsetof(struct rpc_remove_vhost_ctrlr, ctrlr), spdk_json_decode_string },
380 };
381 
382 static void
383 free_rpc_remove_vhost_ctrlr(struct rpc_remove_vhost_ctrlr *req)
384 {
385 	free(req->ctrlr);
386 	free(req);
387 }
388 
389 static int
390 spdk_rpc_remove_vhost_controller_cb(struct spdk_vhost_dev *vdev, void *arg)
391 {
392 	struct rpc_remove_vhost_ctrlr *ctx = arg;
393 	struct spdk_jsonrpc_request *request = ctx->request;
394 	struct spdk_json_write_ctx *w;
395 	int rc;
396 	char buf[64];
397 
398 	if (vdev == NULL) {
399 		rc = -ENODEV;
400 		goto invalid;
401 	}
402 
403 	rc = spdk_remove_vhost_controller(vdev);
404 	if (rc < 0) {
405 		goto invalid;
406 	}
407 
408 	free_rpc_remove_vhost_ctrlr(ctx);
409 
410 	w = spdk_jsonrpc_begin_result(request);
411 	if (w == NULL) {
412 		return 0;
413 	}
414 
415 	spdk_json_write_bool(w, true);
416 	spdk_jsonrpc_end_result(request, w);
417 	return 0;
418 
419 invalid:
420 	free_rpc_remove_vhost_ctrlr(ctx);
421 	spdk_strerror_r(-rc, buf, sizeof(buf));
422 	spdk_jsonrpc_send_error_response(request,
423 					 SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
424 	return -1;
425 }
426 
427 static void
428 spdk_rpc_remove_vhost_controller(struct spdk_jsonrpc_request *request,
429 				 const struct spdk_json_val *params)
430 {
431 	struct rpc_remove_vhost_ctrlr *req;
432 	char buf[64];
433 	int rc;
434 
435 	req = calloc(1, sizeof(*req));
436 	if (req == NULL) {
437 		rc = -ENOMEM;
438 		goto invalid;
439 	}
440 
441 	req->request = request;
442 	if (spdk_json_decode_object(params, rpc_remove_vhost_ctrlr,
443 				    SPDK_COUNTOF(rpc_remove_vhost_ctrlr), req)) {
444 		SPDK_DEBUGLOG(SPDK_TRACE_VHOST_RPC, "spdk_json_decode_object failed\n");
445 		rc = -EINVAL;
446 		goto invalid;
447 	}
448 
449 	spdk_vhost_call_external_event(req->ctrlr, spdk_rpc_remove_vhost_controller_cb, req);
450 	return;
451 
452 invalid:
453 	if (req) {
454 		free_rpc_remove_vhost_ctrlr(req);
455 	}
456 	spdk_strerror_r(-rc, buf, sizeof(buf));
457 	spdk_jsonrpc_send_error_response(request,
458 					 SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
459 
460 }
461 SPDK_RPC_REGISTER("remove_vhost_controller", spdk_rpc_remove_vhost_controller)
462 
463 struct rpc_get_vhost_ctrlrs {
464 	struct spdk_json_write_ctx *w;
465 	struct spdk_jsonrpc_request *request;
466 };
467 
468 static int
469 spdk_rpc_get_vhost_controllers_cb(struct spdk_vhost_dev *vdev, void *arg)
470 {
471 	struct rpc_get_vhost_ctrlrs *ctx = arg;
472 
473 	if (vdev == NULL) {
474 		spdk_json_write_array_end(ctx->w);
475 		spdk_jsonrpc_end_result(ctx->request, ctx->w);
476 		free(ctx);
477 		return 0;
478 	}
479 
480 	spdk_json_write_object_begin(ctx->w);
481 
482 	spdk_json_write_name(ctx->w, "ctrlr");
483 	spdk_json_write_string(ctx->w, spdk_vhost_dev_get_name(vdev));
484 
485 	spdk_json_write_name(ctx->w, "cpumask");
486 	spdk_json_write_string_fmt(ctx->w, "%#" PRIx64, spdk_vhost_dev_get_cpumask(vdev));
487 
488 	spdk_json_write_name(ctx->w, "backend_specific");
489 
490 	spdk_json_write_object_begin(ctx->w);
491 	spdk_vhost_dump_config_json(vdev, ctx->w);
492 	spdk_json_write_object_end(ctx->w);
493 
494 	spdk_json_write_object_end(ctx->w); // ctrl
495 
496 	return 0;
497 }
498 
499 
500 static void
501 spdk_rpc_get_vhost_controllers(struct spdk_jsonrpc_request *request,
502 			       const struct spdk_json_val *params)
503 {
504 	struct rpc_get_vhost_ctrlrs *ctx;
505 	struct spdk_json_write_ctx *w;
506 	char buf[64];
507 
508 	if (params != NULL) {
509 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
510 						 "get_vhost_controllers requires no parameters");
511 		return;
512 	}
513 
514 	w = spdk_jsonrpc_begin_result(request);
515 	if (w == NULL) {
516 		return;
517 	}
518 
519 	spdk_json_write_array_begin(w);
520 
521 	ctx = calloc(1, sizeof(*ctx));
522 	if (ctx == NULL) {
523 		spdk_strerror_r(-ENOMEM, buf, sizeof(buf));
524 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, buf);
525 		return;
526 	}
527 
528 	ctx->w = w;
529 	ctx->request = request;
530 	spdk_vhost_call_external_event_foreach(spdk_rpc_get_vhost_controllers_cb, ctx);
531 }
532 SPDK_RPC_REGISTER("get_vhost_controllers", spdk_rpc_get_vhost_controllers)
533 
534 SPDK_LOG_REGISTER_TRACE_FLAG("vhost_rpc", SPDK_TRACE_VHOST_RPC)
535