]> git.proxmox.com Git - mirror_qemu.git/blame - backends/cryptodev.c
cryptodev: support QoS
[mirror_qemu.git] / backends / cryptodev.c
CommitLineData
d0ee7a13
GA
1/*
2 * QEMU Crypto Device Implementation
3 *
4 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
5 *
6 * Authors:
7 * Gonglei <arei.gonglei@huawei.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
0dda001b 12 * version 2.1 of the License, or (at your option) any later version.
d0ee7a13
GA
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include "qemu/osdep.h"
25#include "sysemu/cryptodev.h"
d0ee7a13 26#include "qapi/error.h"
5dcb0198 27#include "qapi/qapi-commands-cryptodev.h"
d0ee7a13 28#include "qapi/visitor.h"
d0ee7a13 29#include "qemu/config-file.h"
2fda101d 30#include "qemu/error-report.h"
2580b452 31#include "qemu/main-loop.h"
d0ee7a13 32#include "qom/object_interfaces.h"
d6634ac0
GA
33#include "hw/virtio/virtio-crypto.h"
34
d0ee7a13
GA
35
36static QTAILQ_HEAD(, CryptoDevBackendClient) crypto_clients;
37
5dcb0198
ZP
38static int qmp_query_cryptodev_foreach(Object *obj, void *data)
39{
40 CryptoDevBackend *backend;
41 QCryptodevInfoList **infolist = data;
42 uint32_t services, i;
43
44 if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
45 return 0;
46 }
47
48 QCryptodevInfo *info = g_new0(QCryptodevInfo, 1);
49 info->id = g_strdup(object_get_canonical_path_component(obj));
50
51 backend = CRYPTODEV_BACKEND(obj);
52 services = backend->conf.crypto_services;
53 for (i = 0; i < QCRYPTODEV_BACKEND_SERVICE__MAX; i++) {
54 if (services & (1 << i)) {
55 QAPI_LIST_PREPEND(info->service, i);
56 }
57 }
58
59 for (i = 0; i < backend->conf.peers.queues; i++) {
60 CryptoDevBackendClient *cc = backend->conf.peers.ccs[i];
61 QCryptodevBackendClient *client = g_new0(QCryptodevBackendClient, 1);
62
63 client->queue = cc->queue_index;
64 client->type = cc->type;
65 QAPI_LIST_PREPEND(info->client, client);
66 }
67
68 QAPI_LIST_PREPEND(*infolist, info);
69
70 return 0;
71}
72
73QCryptodevInfoList *qmp_query_cryptodev(Error **errp)
74{
75 QCryptodevInfoList *list = NULL;
76 Object *objs = container_get(object_get_root(), "/objects");
77
78 object_child_foreach(objs, qmp_query_cryptodev_foreach, &list);
79
80 return list;
81}
d0ee7a13 82
3f478371 83CryptoDevBackendClient *cryptodev_backend_new_client(void)
d0ee7a13
GA
84{
85 CryptoDevBackendClient *cc;
86
b21e2380 87 cc = g_new0(CryptoDevBackendClient, 1);
d0ee7a13
GA
88 QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
89
90 return cc;
91}
92
93void cryptodev_backend_free_client(
94 CryptoDevBackendClient *cc)
95{
96 QTAILQ_REMOVE(&crypto_clients, cc, next);
d0ee7a13
GA
97 g_free(cc->info_str);
98 g_free(cc);
99}
100
101void cryptodev_backend_cleanup(
102 CryptoDevBackend *backend,
103 Error **errp)
104{
105 CryptoDevBackendClass *bc =
106 CRYPTODEV_BACKEND_GET_CLASS(backend);
107
108 if (bc->cleanup) {
109 bc->cleanup(backend, errp);
110 }
e7a775fd
ZP
111
112 g_free(backend->sym_stat);
113 g_free(backend->asym_stat);
d0ee7a13
GA
114}
115
2fda101d 116int cryptodev_backend_create_session(
9e4f86a8 117 CryptoDevBackend *backend,
0e660a6f 118 CryptoDevBackendSessionInfo *sess_info,
2fda101d
LH
119 uint32_t queue_index,
120 CryptoDevCompletionFunc cb,
121 void *opaque)
9e4f86a8
GA
122{
123 CryptoDevBackendClass *bc =
124 CRYPTODEV_BACKEND_GET_CLASS(backend);
125
126 if (bc->create_session) {
2fda101d 127 return bc->create_session(backend, sess_info, queue_index, cb, opaque);
9e4f86a8 128 }
2fda101d 129 return -VIRTIO_CRYPTO_NOTSUPP;
9e4f86a8
GA
130}
131
0e660a6f 132int cryptodev_backend_close_session(
9e4f86a8
GA
133 CryptoDevBackend *backend,
134 uint64_t session_id,
2fda101d
LH
135 uint32_t queue_index,
136 CryptoDevCompletionFunc cb,
137 void *opaque)
9e4f86a8
GA
138{
139 CryptoDevBackendClass *bc =
140 CRYPTODEV_BACKEND_GET_CLASS(backend);
141
142 if (bc->close_session) {
2fda101d 143 return bc->close_session(backend, session_id, queue_index, cb, opaque);
9e4f86a8 144 }
2fda101d 145 return -VIRTIO_CRYPTO_NOTSUPP;
9e4f86a8
GA
146}
147
0e660a6f 148static int cryptodev_backend_operation(
9e4f86a8 149 CryptoDevBackend *backend,
2cb06927 150 CryptoDevBackendOpInfo *op_info)
9e4f86a8
GA
151{
152 CryptoDevBackendClass *bc =
153 CRYPTODEV_BACKEND_GET_CLASS(backend);
154
0e660a6f 155 if (bc->do_op) {
2cb06927 156 return bc->do_op(backend, op_info);
9e4f86a8 157 }
2fda101d 158 return -VIRTIO_CRYPTO_NOTSUPP;
d6634ac0
GA
159}
160
e7a775fd
ZP
161static int cryptodev_backend_account(CryptoDevBackend *backend,
162 CryptoDevBackendOpInfo *op_info)
163{
164 enum QCryptodevBackendAlgType algtype = op_info->algtype;
165 int len;
166
167 if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
168 CryptoDevBackendAsymOpInfo *asym_op_info = op_info->u.asym_op_info;
169 len = asym_op_info->src_len;
170 switch (op_info->op_code) {
171 case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
172 CryptodevAsymStatIncEncrypt(backend, len);
173 break;
174 case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
175 CryptodevAsymStatIncDecrypt(backend, len);
176 break;
177 case VIRTIO_CRYPTO_AKCIPHER_SIGN:
178 CryptodevAsymStatIncSign(backend, len);
179 break;
180 case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
181 CryptodevAsymStatIncVerify(backend, len);
182 break;
183 default:
184 return -VIRTIO_CRYPTO_NOTSUPP;
185 }
186 } else if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
187 CryptoDevBackendSymOpInfo *sym_op_info = op_info->u.sym_op_info;
188 len = sym_op_info->src_len;
189 switch (op_info->op_code) {
190 case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
191 CryptodevSymStatIncEncrypt(backend, len);
192 break;
193 case VIRTIO_CRYPTO_CIPHER_DECRYPT:
194 CryptodevSymStatIncDecrypt(backend, len);
195 break;
196 default:
197 return -VIRTIO_CRYPTO_NOTSUPP;
198 }
199 } else {
200 error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
201 return -VIRTIO_CRYPTO_NOTSUPP;
202 }
203
204 return len;
205}
206
2580b452
ZP
207static void cryptodev_backend_throttle_timer_cb(void *opaque)
208{
209 CryptoDevBackend *backend = (CryptoDevBackend *)opaque;
210 CryptoDevBackendOpInfo *op_info, *tmpop;
211 int ret;
212
213 QTAILQ_FOREACH_SAFE(op_info, &backend->opinfos, next, tmpop) {
214 QTAILQ_REMOVE(&backend->opinfos, op_info, next);
215 ret = cryptodev_backend_account(backend, op_info);
216 if (ret < 0) {
217 op_info->cb(op_info->opaque, ret);
218 continue;
219 }
220
221 throttle_account(&backend->ts, true, ret);
222 cryptodev_backend_operation(backend, op_info);
223 if (throttle_enabled(&backend->tc) &&
224 throttle_schedule_timer(&backend->ts, &backend->tt, true)) {
225 break;
226 }
227 }
228}
229
d6634ac0
GA
230int cryptodev_backend_crypto_operation(
231 CryptoDevBackend *backend,
2cb06927 232 CryptoDevBackendOpInfo *op_info)
d6634ac0 233{
e7a775fd 234 int ret;
d6634ac0 235
2580b452
ZP
236 if (!throttle_enabled(&backend->tc)) {
237 goto do_account;
238 }
239
240 if (throttle_schedule_timer(&backend->ts, &backend->tt, true) ||
241 !QTAILQ_EMPTY(&backend->opinfos)) {
242 QTAILQ_INSERT_TAIL(&backend->opinfos, op_info, next);
243 return 0;
244 }
245
246do_account:
e7a775fd
ZP
247 ret = cryptodev_backend_account(backend, op_info);
248 if (ret < 0) {
249 return ret;
d6634ac0
GA
250 }
251
2580b452
ZP
252 throttle_account(&backend->ts, true, ret);
253
2cb06927 254 return cryptodev_backend_operation(backend, op_info);
9e4f86a8
GA
255}
256
d0ee7a13
GA
257static void
258cryptodev_backend_get_queues(Object *obj, Visitor *v, const char *name,
259 void *opaque, Error **errp)
260{
261 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
262 uint32_t value = backend->conf.peers.queues;
263
264 visit_type_uint32(v, name, &value, errp);
265}
266
267static void
268cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name,
269 void *opaque, Error **errp)
270{
271 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
d0ee7a13
GA
272 uint32_t value;
273
668f62ec 274 if (!visit_type_uint32(v, name, &value, errp)) {
dcfe4805 275 return;
d0ee7a13
GA
276 }
277 if (!value) {
dcfe4805
MA
278 error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu32 "'",
279 object_get_typename(obj), name, value);
280 return;
d0ee7a13
GA
281 }
282 backend->conf.peers.queues = value;
d0ee7a13
GA
283}
284
2580b452
ZP
285static void cryptodev_backend_set_throttle(CryptoDevBackend *backend, int field,
286 uint64_t value, Error **errp)
287{
288 uint64_t orig = backend->tc.buckets[field].avg;
289 bool enabled = throttle_enabled(&backend->tc);
290
291 if (orig == value) {
292 return;
293 }
294
295 backend->tc.buckets[field].avg = value;
296 if (!throttle_enabled(&backend->tc)) {
297 throttle_timers_destroy(&backend->tt);
298 cryptodev_backend_throttle_timer_cb(backend); /* drain opinfos */
299 return;
300 }
301
302 if (!throttle_is_valid(&backend->tc, errp)) {
303 backend->tc.buckets[field].avg = orig; /* revert change */
304 return;
305 }
306
307 if (!enabled) {
308 throttle_init(&backend->ts);
309 throttle_timers_init(&backend->tt, qemu_get_aio_context(),
310 QEMU_CLOCK_REALTIME,
311 cryptodev_backend_throttle_timer_cb, /* FIXME */
312 cryptodev_backend_throttle_timer_cb, backend);
313 }
314
315 throttle_config(&backend->ts, QEMU_CLOCK_REALTIME, &backend->tc);
316}
317
318static void cryptodev_backend_get_bps(Object *obj, Visitor *v,
319 const char *name, void *opaque,
320 Error **errp)
321{
322 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
323 uint64_t value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
324
325 visit_type_uint64(v, name, &value, errp);
326}
327
328static void cryptodev_backend_set_bps(Object *obj, Visitor *v, const char *name,
329 void *opaque, Error **errp)
330{
331 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
332 uint64_t value;
333
334 if (!visit_type_uint64(v, name, &value, errp)) {
335 return;
336 }
337
338 cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
339}
340
341static void cryptodev_backend_get_ops(Object *obj, Visitor *v, const char *name,
342 void *opaque, Error **errp)
343{
344 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
345 uint64_t value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
346
347 visit_type_uint64(v, name, &value, errp);
348}
349
350static void cryptodev_backend_set_ops(Object *obj, Visitor *v,
351 const char *name, void *opaque,
352 Error **errp)
353{
354 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
355 uint64_t value;
356
357 if (!visit_type_uint64(v, name, &value, errp)) {
358 return;
359 }
360
361 cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
362}
363
d0ee7a13
GA
364static void
365cryptodev_backend_complete(UserCreatable *uc, Error **errp)
366{
367 CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
368 CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
e7a775fd 369 uint32_t services;
2580b452
ZP
370 uint64_t value;
371
372 QTAILQ_INIT(&backend->opinfos);
373 value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
374 cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
375 value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
376 cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
d0ee7a13
GA
377
378 if (bc->init) {
7dc75edb 379 bc->init(backend, errp);
d0ee7a13 380 }
e7a775fd
ZP
381
382 services = backend->conf.crypto_services;
383 if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) {
384 backend->sym_stat = g_new0(CryptodevBackendSymStat, 1);
385 }
386
387 if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) {
388 backend->asym_stat = g_new0(CryptodevBackendAsymStat, 1);
389 }
d0ee7a13
GA
390}
391
46fd1705
GA
392void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
393{
394 backend->is_used = used;
395}
396
397bool cryptodev_backend_is_used(CryptoDevBackend *backend)
398{
399 return backend->is_used;
400}
401
6138dbda
GA
402void cryptodev_backend_set_ready(CryptoDevBackend *backend, bool ready)
403{
404 backend->ready = ready;
405}
406
407bool cryptodev_backend_is_ready(CryptoDevBackend *backend)
408{
409 return backend->ready;
410}
411
46fd1705 412static bool
3beacfb9 413cryptodev_backend_can_be_deleted(UserCreatable *uc)
46fd1705
GA
414{
415 return !cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc));
416}
417
d0ee7a13
GA
418static void cryptodev_backend_instance_init(Object *obj)
419{
2580b452
ZP
420 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
421
d0ee7a13 422 /* Initialize devices' queues property to 1 */
5325cc34 423 object_property_set_int(obj, "queues", 1, NULL);
2580b452
ZP
424
425 throttle_config_init(&backend->tc);
d0ee7a13
GA
426}
427
428static void cryptodev_backend_finalize(Object *obj)
429{
46fd1705 430 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
d0ee7a13 431
46fd1705 432 cryptodev_backend_cleanup(backend, NULL);
2580b452
ZP
433 if (throttle_enabled(&backend->tc)) {
434 throttle_timers_destroy(&backend->tt);
435 }
d0ee7a13
GA
436}
437
438static void
439cryptodev_backend_class_init(ObjectClass *oc, void *data)
440{
441 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
442
443 ucc->complete = cryptodev_backend_complete;
46fd1705 444 ucc->can_be_deleted = cryptodev_backend_can_be_deleted;
d0ee7a13
GA
445
446 QTAILQ_INIT(&crypto_clients);
1f14e388
EH
447 object_class_property_add(oc, "queues", "uint32",
448 cryptodev_backend_get_queues,
449 cryptodev_backend_set_queues,
450 NULL, NULL);
2580b452
ZP
451 object_class_property_add(oc, "throttle-bps", "uint64",
452 cryptodev_backend_get_bps,
453 cryptodev_backend_set_bps,
454 NULL, NULL);
455 object_class_property_add(oc, "throttle-ops", "uint64",
456 cryptodev_backend_get_ops,
457 cryptodev_backend_set_ops,
458 NULL, NULL);
d0ee7a13
GA
459}
460
461static const TypeInfo cryptodev_backend_info = {
462 .name = TYPE_CRYPTODEV_BACKEND,
463 .parent = TYPE_OBJECT,
464 .instance_size = sizeof(CryptoDevBackend),
465 .instance_init = cryptodev_backend_instance_init,
466 .instance_finalize = cryptodev_backend_finalize,
467 .class_size = sizeof(CryptoDevBackendClass),
468 .class_init = cryptodev_backend_class_init,
469 .interfaces = (InterfaceInfo[]) {
470 { TYPE_USER_CREATABLE },
471 { }
472 }
473};
474
475static void
476cryptodev_backend_register_types(void)
477{
478 type_register_static(&cryptodev_backend_info);
479}
480
481type_init(cryptodev_backend_register_types);