xref: /spdk/lib/vhost/vhost_rpc.c (revision 60982c759db49b4f4579f16e3b24df0725ba4b94)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2017 Intel Corporation. All rights reserved.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk/log.h"
9 #include "spdk/rpc.h"
10 #include "spdk/util.h"
11 #include "spdk/string.h"
12 #include "spdk/env.h"
13 #include "spdk/log.h"
14 #include "spdk/scsi.h"
15 #include "spdk/vhost.h"
16 #include "vhost_internal.h"
17 #include "spdk/bdev.h"
18 
19 struct rpc_vhost_scsi_ctrlr {
20 	char *ctrlr;
21 	char *cpumask;
22 };
23 
24 static void
25 free_rpc_vhost_scsi_ctrlr(struct rpc_vhost_scsi_ctrlr *req)
26 {
27 	free(req->ctrlr);
28 	free(req->cpumask);
29 }
30 
31 static const struct spdk_json_object_decoder rpc_vhost_create_scsi_ctrlr[] = {
32 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
33 	{"cpumask", offsetof(struct rpc_vhost_scsi_ctrlr, cpumask), spdk_json_decode_string, true},
34 };
35 
36 static void
37 rpc_vhost_create_scsi_controller(struct spdk_jsonrpc_request *request,
38 				 const struct spdk_json_val *params)
39 {
40 	struct rpc_vhost_scsi_ctrlr req = {0};
41 	int rc;
42 
43 	if (spdk_json_decode_object(params, rpc_vhost_create_scsi_ctrlr,
44 				    SPDK_COUNTOF(rpc_vhost_create_scsi_ctrlr),
45 				    &req)) {
46 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
47 		rc = -EINVAL;
48 		goto invalid;
49 	}
50 
51 	rc = spdk_vhost_scsi_dev_construct(req.ctrlr, req.cpumask);
52 	if (rc < 0) {
53 		goto invalid;
54 	}
55 
56 	free_rpc_vhost_scsi_ctrlr(&req);
57 
58 	spdk_jsonrpc_send_bool_response(request, true);
59 	return;
60 
61 invalid:
62 	free_rpc_vhost_scsi_ctrlr(&req);
63 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
64 					 spdk_strerror(-rc));
65 }
66 SPDK_RPC_REGISTER("vhost_create_scsi_controller", rpc_vhost_create_scsi_controller,
67 		  SPDK_RPC_RUNTIME)
68 
69 struct rpc_vhost_scsi_ctrlr_add_target {
70 	char *ctrlr;
71 	int32_t scsi_target_num;
72 	char *bdev_name;
73 };
74 
75 static void
76 free_rpc_vhost_scsi_ctrlr_add_target(struct rpc_vhost_scsi_ctrlr_add_target *req)
77 {
78 	free(req->ctrlr);
79 	free(req->bdev_name);
80 }
81 
82 static const struct spdk_json_object_decoder rpc_vhost_scsi_ctrlr_add_target[] = {
83 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, ctrlr), spdk_json_decode_string },
84 	{"scsi_target_num", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, scsi_target_num), spdk_json_decode_int32},
85 	{"bdev_name", offsetof(struct rpc_vhost_scsi_ctrlr_add_target, bdev_name), spdk_json_decode_string },
86 };
87 
88 static void
89 rpc_vhost_scsi_controller_add_target(struct spdk_jsonrpc_request *request,
90 				     const struct spdk_json_val *params)
91 {
92 	struct rpc_vhost_scsi_ctrlr_add_target req = {0};
93 	struct spdk_json_write_ctx *w;
94 	struct spdk_vhost_dev *vdev;
95 	int rc;
96 
97 	if (spdk_json_decode_object(params, rpc_vhost_scsi_ctrlr_add_target,
98 				    SPDK_COUNTOF(rpc_vhost_scsi_ctrlr_add_target),
99 				    &req)) {
100 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
101 		rc = -EINVAL;
102 		goto invalid;
103 	}
104 
105 	spdk_vhost_lock();
106 	vdev = spdk_vhost_dev_find(req.ctrlr);
107 	if (vdev == NULL) {
108 		spdk_vhost_unlock();
109 		rc = -ENODEV;
110 		goto invalid;
111 	}
112 
113 	rc = spdk_vhost_scsi_dev_add_tgt(vdev, req.scsi_target_num, req.bdev_name);
114 	spdk_vhost_unlock();
115 	if (rc < 0) {
116 		goto invalid;
117 	}
118 
119 	free_rpc_vhost_scsi_ctrlr_add_target(&req);
120 
121 	w = spdk_jsonrpc_begin_result(request);
122 	spdk_json_write_int32(w, rc);
123 	spdk_jsonrpc_end_result(request, w);
124 	return;
125 
126 invalid:
127 	free_rpc_vhost_scsi_ctrlr_add_target(&req);
128 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
129 					 spdk_strerror(-rc));
130 }
131 SPDK_RPC_REGISTER("vhost_scsi_controller_add_target", rpc_vhost_scsi_controller_add_target,
132 		  SPDK_RPC_RUNTIME)
133 
134 struct rpc_remove_vhost_scsi_ctrlr_target {
135 	char *ctrlr;
136 	uint32_t scsi_target_num;
137 };
138 
139 static void
140 free_rpc_remove_vhost_scsi_ctrlr_target(struct rpc_remove_vhost_scsi_ctrlr_target *req)
141 {
142 	free(req->ctrlr);
143 }
144 
145 static const struct spdk_json_object_decoder rpc_vhost_remove_target[] = {
146 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, ctrlr), spdk_json_decode_string },
147 	{"scsi_target_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_target, scsi_target_num), spdk_json_decode_uint32},
148 };
149 
150 static int
151 rpc_vhost_scsi_controller_remove_target_finish_cb(struct spdk_vhost_dev *vdev, void *arg)
152 {
153 	struct spdk_jsonrpc_request *request = arg;
154 
155 	spdk_jsonrpc_send_bool_response(request, true);
156 	return 0;
157 }
158 
159 static void
160 rpc_vhost_scsi_controller_remove_target(struct spdk_jsonrpc_request *request,
161 					const struct spdk_json_val *params)
162 {
163 	struct rpc_remove_vhost_scsi_ctrlr_target req = {0};
164 	struct spdk_vhost_dev *vdev;
165 	int rc;
166 
167 	if (spdk_json_decode_object(params, rpc_vhost_remove_target,
168 				    SPDK_COUNTOF(rpc_vhost_remove_target),
169 				    &req)) {
170 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
171 		rc = -EINVAL;
172 		goto invalid;
173 	}
174 
175 	spdk_vhost_lock();
176 	vdev = spdk_vhost_dev_find(req.ctrlr);
177 	if (vdev == NULL) {
178 		spdk_vhost_unlock();
179 		rc = -ENODEV;
180 		goto invalid;
181 	}
182 
183 	rc = spdk_vhost_scsi_dev_remove_tgt(vdev, req.scsi_target_num,
184 					    rpc_vhost_scsi_controller_remove_target_finish_cb,
185 					    request);
186 	spdk_vhost_unlock();
187 	if (rc < 0) {
188 		goto invalid;
189 	}
190 
191 	free_rpc_remove_vhost_scsi_ctrlr_target(&req);
192 	return;
193 
194 invalid:
195 	free_rpc_remove_vhost_scsi_ctrlr_target(&req);
196 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
197 					 spdk_strerror(-rc));
198 }
199 
200 SPDK_RPC_REGISTER("vhost_scsi_controller_remove_target",
201 		  rpc_vhost_scsi_controller_remove_target, SPDK_RPC_RUNTIME)
202 
203 struct rpc_vhost_blk_ctrlr {
204 	char *ctrlr;
205 	char *dev_name;
206 	char *cpumask;
207 	char *transport;
208 };
209 
210 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
211 	{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
212 	{"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string },
213 	{"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true},
214 	{"transport", offsetof(struct rpc_vhost_blk_ctrlr, transport), spdk_json_decode_string, true},
215 };
216 
217 static void
218 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
219 {
220 	free(req->ctrlr);
221 	free(req->dev_name);
222 	free(req->cpumask);
223 	free(req->transport);
224 }
225 
226 static void
227 rpc_vhost_create_blk_controller(struct spdk_jsonrpc_request *request,
228 				const struct spdk_json_val *params)
229 {
230 	struct rpc_vhost_blk_ctrlr req = {0};
231 	int rc;
232 
233 	if (spdk_json_decode_object_relaxed(params, rpc_construct_vhost_blk_ctrlr,
234 					    SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr),
235 					    &req)) {
236 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
237 		rc = -EINVAL;
238 		goto invalid;
239 	}
240 
241 	rc = spdk_vhost_blk_construct(req.ctrlr, req.cpumask, req.dev_name, req.transport, params);
242 	if (rc < 0) {
243 		goto invalid;
244 	}
245 
246 	free_rpc_vhost_blk_ctrlr(&req);
247 
248 	spdk_jsonrpc_send_bool_response(request, true);
249 	return;
250 
251 invalid:
252 	free_rpc_vhost_blk_ctrlr(&req);
253 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
254 					 spdk_strerror(-rc));
255 
256 }
257 SPDK_RPC_REGISTER("vhost_create_blk_controller", rpc_vhost_create_blk_controller,
258 		  SPDK_RPC_RUNTIME)
259 
260 struct rpc_delete_vhost_ctrlr {
261 	char *ctrlr;
262 };
263 
264 static const struct spdk_json_object_decoder rpc_delete_vhost_ctrlr_decoder[] = {
265 	{"ctrlr", offsetof(struct rpc_delete_vhost_ctrlr, ctrlr), spdk_json_decode_string },
266 };
267 
268 static void
269 free_rpc_delete_vhost_ctrlr(struct rpc_delete_vhost_ctrlr *req)
270 {
271 	free(req->ctrlr);
272 }
273 
274 static void
275 rpc_vhost_delete_controller(struct spdk_jsonrpc_request *request,
276 			    const struct spdk_json_val *params)
277 {
278 	struct rpc_delete_vhost_ctrlr req = {0};
279 	struct spdk_vhost_dev *vdev;
280 	int rc;
281 
282 	if (spdk_json_decode_object(params, rpc_delete_vhost_ctrlr_decoder,
283 				    SPDK_COUNTOF(rpc_delete_vhost_ctrlr_decoder), &req)) {
284 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
285 		rc = -EINVAL;
286 		goto invalid;
287 	}
288 
289 	spdk_vhost_lock();
290 	vdev = spdk_vhost_dev_find(req.ctrlr);
291 	if (vdev == NULL) {
292 		spdk_vhost_unlock();
293 		rc = -ENODEV;
294 		goto invalid;
295 	}
296 	spdk_vhost_unlock();
297 
298 	rc = spdk_vhost_dev_remove(vdev);
299 	if (rc < 0) {
300 		goto invalid;
301 	}
302 
303 	free_rpc_delete_vhost_ctrlr(&req);
304 
305 	spdk_jsonrpc_send_bool_response(request, true);
306 	return;
307 
308 invalid:
309 	free_rpc_delete_vhost_ctrlr(&req);
310 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
311 					 spdk_strerror(-rc));
312 
313 }
314 SPDK_RPC_REGISTER("vhost_delete_controller", rpc_vhost_delete_controller, SPDK_RPC_RUNTIME)
315 
316 struct rpc_get_vhost_ctrlrs {
317 	char *name;
318 };
319 
320 static void
321 _rpc_get_vhost_controller(struct spdk_json_write_ctx *w, struct spdk_vhost_dev *vdev)
322 {
323 	uint32_t delay_base_us, iops_threshold;
324 
325 	spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold);
326 
327 	spdk_json_write_object_begin(w);
328 
329 	spdk_json_write_named_string(w, "ctrlr", spdk_vhost_dev_get_name(vdev));
330 	spdk_json_write_named_string_fmt(w, "cpumask", "0x%s",
331 					 spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
332 	spdk_json_write_named_uint32(w, "delay_base_us", delay_base_us);
333 	spdk_json_write_named_uint32(w, "iops_threshold", iops_threshold);
334 	spdk_json_write_named_string(w, "socket", vdev->path);
335 	spdk_json_write_named_array_begin(w, "sessions");
336 	vhost_session_info_json(vdev, w);
337 	spdk_json_write_array_end(w);
338 
339 	spdk_json_write_named_object_begin(w, "backend_specific");
340 	vhost_dump_info_json(vdev, w);
341 	spdk_json_write_object_end(w);
342 
343 	spdk_json_write_object_end(w);
344 }
345 
346 static const struct spdk_json_object_decoder rpc_get_vhost_ctrlrs_decoders[] = {
347 	{"name", offsetof(struct rpc_get_vhost_ctrlrs, name), spdk_json_decode_string, true},
348 };
349 
350 static void
351 free_rpc_get_vhost_ctrlrs(struct rpc_get_vhost_ctrlrs *req)
352 {
353 	free(req->name);
354 }
355 
356 static void
357 rpc_vhost_get_controllers(struct spdk_jsonrpc_request *request,
358 			  const struct spdk_json_val *params)
359 {
360 	struct rpc_get_vhost_ctrlrs req = {0};
361 	struct spdk_json_write_ctx *w;
362 	struct spdk_vhost_dev *vdev;
363 	int rc;
364 
365 	if (params && spdk_json_decode_object(params, rpc_get_vhost_ctrlrs_decoders,
366 					      SPDK_COUNTOF(rpc_get_vhost_ctrlrs_decoders), &req)) {
367 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
368 		rc = -EINVAL;
369 		goto invalid;
370 	}
371 
372 	spdk_vhost_lock();
373 	if (req.name != NULL) {
374 		vdev = spdk_vhost_dev_find(req.name);
375 		if (vdev == NULL) {
376 			spdk_vhost_unlock();
377 			rc = -ENODEV;
378 			goto invalid;
379 		}
380 
381 		free_rpc_get_vhost_ctrlrs(&req);
382 
383 		w = spdk_jsonrpc_begin_result(request);
384 		spdk_json_write_array_begin(w);
385 
386 		_rpc_get_vhost_controller(w, vdev);
387 		spdk_vhost_unlock();
388 
389 		spdk_json_write_array_end(w);
390 		spdk_jsonrpc_end_result(request, w);
391 		return;
392 	}
393 
394 	free_rpc_get_vhost_ctrlrs(&req);
395 
396 	w = spdk_jsonrpc_begin_result(request);
397 	spdk_json_write_array_begin(w);
398 
399 	vdev = spdk_vhost_dev_next(NULL);
400 	while (vdev != NULL) {
401 		_rpc_get_vhost_controller(w, vdev);
402 		vdev = spdk_vhost_dev_next(vdev);
403 	}
404 	spdk_vhost_unlock();
405 
406 	spdk_json_write_array_end(w);
407 	spdk_jsonrpc_end_result(request, w);
408 	return;
409 
410 invalid:
411 	free_rpc_get_vhost_ctrlrs(&req);
412 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
413 					 spdk_strerror(-rc));
414 }
415 SPDK_RPC_REGISTER("vhost_get_controllers", rpc_vhost_get_controllers, SPDK_RPC_RUNTIME)
416 
417 
418 struct rpc_vhost_ctrlr_coalescing {
419 	char *ctrlr;
420 	uint32_t delay_base_us;
421 	uint32_t iops_threshold;
422 };
423 
424 static const struct spdk_json_object_decoder rpc_set_vhost_ctrlr_coalescing[] = {
425 	{"ctrlr", offsetof(struct rpc_vhost_ctrlr_coalescing, ctrlr), spdk_json_decode_string },
426 	{"delay_base_us", offsetof(struct rpc_vhost_ctrlr_coalescing, delay_base_us), spdk_json_decode_uint32},
427 	{"iops_threshold", offsetof(struct rpc_vhost_ctrlr_coalescing, iops_threshold), spdk_json_decode_uint32},
428 };
429 
430 static void
431 free_rpc_set_vhost_controllers_event_coalescing(struct rpc_vhost_ctrlr_coalescing *req)
432 {
433 	free(req->ctrlr);
434 }
435 
436 static void
437 rpc_vhost_controller_set_coalescing(struct spdk_jsonrpc_request *request,
438 				    const struct spdk_json_val *params)
439 {
440 	struct rpc_vhost_ctrlr_coalescing req = {0};
441 	struct spdk_vhost_dev *vdev;
442 	int rc;
443 
444 	if (spdk_json_decode_object(params, rpc_set_vhost_ctrlr_coalescing,
445 				    SPDK_COUNTOF(rpc_set_vhost_ctrlr_coalescing), &req)) {
446 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
447 		rc = -EINVAL;
448 		goto invalid;
449 	}
450 
451 	spdk_vhost_lock();
452 	vdev = spdk_vhost_dev_find(req.ctrlr);
453 	if (vdev == NULL) {
454 		spdk_vhost_unlock();
455 		rc = -ENODEV;
456 		goto invalid;
457 	}
458 
459 	rc = spdk_vhost_set_coalescing(vdev, req.delay_base_us, req.iops_threshold);
460 	spdk_vhost_unlock();
461 	if (rc) {
462 		goto invalid;
463 	}
464 
465 	free_rpc_set_vhost_controllers_event_coalescing(&req);
466 
467 	spdk_jsonrpc_send_bool_response(request, true);
468 	return;
469 
470 invalid:
471 	free_rpc_set_vhost_controllers_event_coalescing(&req);
472 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
473 					 spdk_strerror(-rc));
474 }
475 SPDK_RPC_REGISTER("vhost_controller_set_coalescing", rpc_vhost_controller_set_coalescing,
476 		  SPDK_RPC_RUNTIME)
477 
478 struct rpc_get_transport {
479 	char *name;
480 };
481 
482 static const struct spdk_json_object_decoder rpc_get_transport_decoders[] = {
483 	{"name", offsetof(struct rpc_get_transport, name), spdk_json_decode_string, true},
484 };
485 
486 static void
487 rpc_virtio_blk_get_transports(struct spdk_jsonrpc_request *request,
488 			      const struct spdk_json_val *params)
489 {
490 	struct rpc_get_transport req = { 0 };
491 	struct spdk_json_write_ctx *w;
492 	struct spdk_virtio_blk_transport *transport = NULL;
493 
494 	if (params) {
495 		if (spdk_json_decode_object(params, rpc_get_transport_decoders,
496 					    SPDK_COUNTOF(rpc_get_transport_decoders),
497 					    &req)) {
498 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
499 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
500 			return;
501 		}
502 	}
503 
504 	if (req.name) {
505 		transport = virtio_blk_tgt_get_transport(req.name);
506 		if (transport == NULL) {
507 			SPDK_ERRLOG("transport '%s' does not exist\n", req.name);
508 			spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
509 			free(req.name);
510 			return;
511 		}
512 	}
513 
514 	w = spdk_jsonrpc_begin_result(request);
515 	spdk_json_write_array_begin(w);
516 
517 	if (transport) {
518 		virtio_blk_transport_dump_opts(transport, w);
519 	} else {
520 		for (transport = virtio_blk_transport_get_first(); transport != NULL;
521 		     transport = virtio_blk_transport_get_next(transport)) {
522 			virtio_blk_transport_dump_opts(transport, w);
523 		}
524 	}
525 
526 	spdk_json_write_array_end(w);
527 	spdk_jsonrpc_end_result(request, w);
528 	free(req.name);
529 }
530 SPDK_RPC_REGISTER("virtio_blk_get_transports", rpc_virtio_blk_get_transports, SPDK_RPC_RUNTIME)
531 
532 struct rpc_virtio_blk_create_transport {
533 	char *name;
534 };
535 
536 static const struct spdk_json_object_decoder rpc_create_virtio_blk_transport[] = {
537 	{"name", offsetof(struct rpc_virtio_blk_create_transport, name), spdk_json_decode_string},
538 };
539 
540 static void
541 free_rpc_virtio_blk_create_transport(struct rpc_virtio_blk_create_transport *req)
542 {
543 	free(req->name);
544 }
545 
546 static void
547 rpc_virtio_blk_create_transport(struct spdk_jsonrpc_request *request,
548 				const struct spdk_json_val *params)
549 {
550 	struct rpc_virtio_blk_create_transport req = {0};
551 	int rc;
552 
553 	if (spdk_json_decode_object_relaxed(params, rpc_create_virtio_blk_transport,
554 					    SPDK_COUNTOF(rpc_create_virtio_blk_transport), &req)) {
555 		SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
556 		rc = -EINVAL;
557 		goto invalid;
558 	}
559 
560 	spdk_vhost_lock();
561 	rc = virtio_blk_transport_create(req.name, params);
562 	spdk_vhost_unlock();
563 	if (rc != 0) {
564 		goto invalid;
565 	}
566 
567 	free_rpc_virtio_blk_create_transport(&req);
568 	spdk_jsonrpc_send_bool_response(request, true);
569 	return;
570 
571 invalid:
572 	free_rpc_virtio_blk_create_transport(&req);
573 	spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
574 }
575 SPDK_RPC_REGISTER("virtio_blk_create_transport", rpc_virtio_blk_create_transport,
576 		  SPDK_RPC_RUNTIME)
577 
578 SPDK_LOG_REGISTER_COMPONENT(vhost_rpc)
579