2018-03-01 14:46:28 +01:00
|
|
|
/*
|
|
|
|
* QEMU Cryptodev backend for QEMU cipher APIs
|
|
|
|
*
|
|
|
|
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Gonglei <arei.gonglei@huawei.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "qapi/error.h"
|
|
|
|
#include "qapi/qmp/qerror.h"
|
|
|
|
#include "qemu/error-report.h"
|
2018-05-24 12:33:33 +02:00
|
|
|
#include "hw/virtio/vhost-user.h"
|
2018-03-01 14:46:28 +01:00
|
|
|
#include "standard-headers/linux/virtio_crypto.h"
|
|
|
|
#include "sysemu/cryptodev-vhost.h"
|
|
|
|
#include "chardev/char-fe.h"
|
2018-03-01 14:46:29 +01:00
|
|
|
#include "sysemu/cryptodev-vhost-user.h"
|
2018-03-01 14:46:28 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @TYPE_CRYPTODEV_BACKEND_VHOST_USER:
|
|
|
|
* name of backend that uses vhost user server
|
|
|
|
*/
|
|
|
|
#define TYPE_CRYPTODEV_BACKEND_VHOST_USER "cryptodev-vhost-user"
|
|
|
|
|
|
|
|
#define CRYPTODEV_BACKEND_VHOST_USER(obj) \
|
|
|
|
OBJECT_CHECK(CryptoDevBackendVhostUser, \
|
|
|
|
(obj), TYPE_CRYPTODEV_BACKEND_VHOST_USER)
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct CryptoDevBackendVhostUser {
|
|
|
|
CryptoDevBackend parent_obj;
|
|
|
|
|
2019-03-08 15:04:45 +01:00
|
|
|
VhostUserState vhost_user;
|
2018-03-01 14:46:28 +01:00
|
|
|
CharBackend chr;
|
|
|
|
char *chr_name;
|
|
|
|
bool opened;
|
|
|
|
CryptoDevBackendVhost *vhost_crypto[MAX_CRYPTO_QUEUE_NUM];
|
|
|
|
} CryptoDevBackendVhostUser;
|
|
|
|
|
|
|
|
static int
|
|
|
|
cryptodev_vhost_user_running(
|
|
|
|
CryptoDevBackendVhost *crypto)
|
|
|
|
{
|
|
|
|
return crypto ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2018-03-01 14:46:29 +01:00
|
|
|
CryptoDevBackendVhost *
|
|
|
|
cryptodev_vhost_user_get_vhost(
|
|
|
|
CryptoDevBackendClient *cc,
|
|
|
|
CryptoDevBackend *b,
|
|
|
|
uint16_t queue)
|
|
|
|
{
|
|
|
|
CryptoDevBackendVhostUser *s =
|
|
|
|
CRYPTODEV_BACKEND_VHOST_USER(b);
|
|
|
|
assert(cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER);
|
|
|
|
assert(queue < MAX_CRYPTO_QUEUE_NUM);
|
|
|
|
|
|
|
|
return s->vhost_crypto[queue];
|
|
|
|
}
|
|
|
|
|
2018-03-01 14:46:28 +01:00
|
|
|
static void cryptodev_vhost_user_stop(int queues,
|
|
|
|
CryptoDevBackendVhostUser *s)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < queues; i++) {
|
|
|
|
if (!cryptodev_vhost_user_running(s->vhost_crypto[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
cryptodev_vhost_cleanup(s->vhost_crypto[i]);
|
|
|
|
s->vhost_crypto[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
cryptodev_vhost_user_start(int queues,
|
|
|
|
CryptoDevBackendVhostUser *s)
|
|
|
|
{
|
|
|
|
CryptoDevBackendVhostOptions options;
|
|
|
|
CryptoDevBackend *b = CRYPTODEV_BACKEND(s);
|
|
|
|
int max_queues;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < queues; i++) {
|
|
|
|
if (cryptodev_vhost_user_running(s->vhost_crypto[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-03-08 15:04:45 +01:00
|
|
|
options.opaque = &s->vhost_user;
|
2018-03-01 14:46:28 +01:00
|
|
|
options.backend_type = VHOST_BACKEND_TYPE_USER;
|
|
|
|
options.cc = b->conf.peers.ccs[i];
|
|
|
|
s->vhost_crypto[i] = cryptodev_vhost_init(&options);
|
|
|
|
if (!s->vhost_crypto[i]) {
|
|
|
|
error_report("failed to init vhost_crypto for queue %zu", i);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
max_queues =
|
|
|
|
cryptodev_vhost_get_max_queues(s->vhost_crypto[i]);
|
|
|
|
if (queues > max_queues) {
|
|
|
|
error_report("you are asking more queues than supported: %d",
|
|
|
|
max_queues);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
cryptodev_vhost_user_stop(i + 1, s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Chardev *
|
|
|
|
cryptodev_vhost_claim_chardev(CryptoDevBackendVhostUser *s,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
Chardev *chr;
|
|
|
|
|
|
|
|
if (s->chr_name == NULL) {
|
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
|
|
|
|
"chardev", "a valid character device");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
chr = qemu_chr_find(s->chr_name);
|
|
|
|
if (chr == NULL) {
|
|
|
|
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
|
|
"Device '%s' not found", s->chr_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return chr;
|
|
|
|
}
|
|
|
|
|
chardev: Use QEMUChrEvent enum in IOEventHandler typedef
The Chardev events are listed in the QEMUChrEvent enum.
By using the enum in the IOEventHandler typedef we:
- make the IOEventHandler type more explicit (this handler
process out-of-band information, while the IOReadHandler
is in-band),
- help static code analyzers.
This patch was produced with the following spatch script:
@match@
expression backend, opaque, context, set_open;
identifier fd_can_read, fd_read, fd_event, be_change;
@@
qemu_chr_fe_set_handlers(backend, fd_can_read, fd_read, fd_event,
be_change, opaque, context, set_open);
@depends on match@
identifier opaque, event;
identifier match.fd_event;
@@
static
-void fd_event(void *opaque, int event)
+void fd_event(void *opaque, QEMUChrEvent event)
{
...
}
Then the typedef was modified manually in
include/chardev/char-fe.h.
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Acked-by: Corey Minyard <cminyard@mvista.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20191218172009.8868-15-philmd@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2019-12-18 18:20:09 +01:00
|
|
|
static void cryptodev_vhost_user_event(void *opaque, QEMUChrEvent event)
|
2018-03-01 14:46:28 +01:00
|
|
|
{
|
|
|
|
CryptoDevBackendVhostUser *s = opaque;
|
|
|
|
CryptoDevBackend *b = CRYPTODEV_BACKEND(s);
|
|
|
|
int queues = b->conf.peers.queues;
|
|
|
|
|
|
|
|
assert(queues < MAX_CRYPTO_QUEUE_NUM);
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case CHR_EVENT_OPENED:
|
|
|
|
if (cryptodev_vhost_user_start(queues, s) < 0) {
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
b->ready = true;
|
|
|
|
break;
|
|
|
|
case CHR_EVENT_CLOSED:
|
|
|
|
b->ready = false;
|
|
|
|
cryptodev_vhost_user_stop(queues, s);
|
|
|
|
break;
|
2019-12-18 18:20:02 +01:00
|
|
|
case CHR_EVENT_BREAK:
|
|
|
|
case CHR_EVENT_MUX_IN:
|
|
|
|
case CHR_EVENT_MUX_OUT:
|
|
|
|
/* Ignore */
|
|
|
|
break;
|
2018-03-01 14:46:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cryptodev_vhost_user_init(
|
|
|
|
CryptoDevBackend *backend, Error **errp)
|
|
|
|
{
|
|
|
|
int queues = backend->conf.peers.queues;
|
|
|
|
size_t i;
|
|
|
|
Error *local_err = NULL;
|
|
|
|
Chardev *chr;
|
|
|
|
CryptoDevBackendClient *cc;
|
|
|
|
CryptoDevBackendVhostUser *s =
|
|
|
|
CRYPTODEV_BACKEND_VHOST_USER(backend);
|
|
|
|
|
|
|
|
chr = cryptodev_vhost_claim_chardev(s, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->opened = true;
|
|
|
|
|
|
|
|
for (i = 0; i < queues; i++) {
|
|
|
|
cc = cryptodev_backend_new_client(
|
|
|
|
"cryptodev-vhost-user", NULL);
|
|
|
|
cc->info_str = g_strdup_printf("cryptodev-vhost-user%zu to %s ",
|
|
|
|
i, chr->label);
|
|
|
|
cc->queue_index = i;
|
2018-03-01 14:46:29 +01:00
|
|
|
cc->type = CRYPTODEV_BACKEND_TYPE_VHOST_USER;
|
2018-03-01 14:46:28 +01:00
|
|
|
|
|
|
|
backend->conf.peers.ccs[i] = cc;
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
if (!qemu_chr_fe_init(&s->chr, chr, &local_err)) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-08 15:04:45 +01:00
|
|
|
if (!vhost_user_init(&s->vhost_user, &s->chr, errp)) {
|
2018-05-24 12:33:33 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-01 14:46:28 +01:00
|
|
|
qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
|
|
|
|
cryptodev_vhost_user_event, NULL, s, NULL, true);
|
|
|
|
|
|
|
|
backend->conf.crypto_services =
|
|
|
|
1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
|
|
|
|
1u << VIRTIO_CRYPTO_SERVICE_HASH |
|
|
|
|
1u << VIRTIO_CRYPTO_SERVICE_MAC;
|
|
|
|
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
|
|
|
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
2018-03-01 14:46:31 +01:00
|
|
|
|
|
|
|
backend->conf.max_size = UINT64_MAX;
|
|
|
|
backend->conf.max_cipher_key_len = VHOST_USER_MAX_CIPHER_KEY_LEN;
|
|
|
|
backend->conf.max_auth_key_len = VHOST_USER_MAX_AUTH_KEY_LEN;
|
2018-03-01 14:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t cryptodev_vhost_user_sym_create_session(
|
|
|
|
CryptoDevBackend *backend,
|
|
|
|
CryptoDevBackendSymSessionInfo *sess_info,
|
|
|
|
uint32_t queue_index, Error **errp)
|
|
|
|
{
|
2018-03-01 14:46:30 +01:00
|
|
|
CryptoDevBackendClient *cc =
|
|
|
|
backend->conf.peers.ccs[queue_index];
|
|
|
|
CryptoDevBackendVhost *vhost_crypto;
|
|
|
|
uint64_t session_id = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
vhost_crypto = cryptodev_vhost_user_get_vhost(cc, backend, queue_index);
|
|
|
|
if (vhost_crypto) {
|
|
|
|
struct vhost_dev *dev = &(vhost_crypto->dev);
|
|
|
|
ret = dev->vhost_ops->vhost_crypto_create_session(dev,
|
|
|
|
sess_info,
|
|
|
|
&session_id);
|
|
|
|
if (ret < 0) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return session_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
2018-03-01 14:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int cryptodev_vhost_user_sym_close_session(
|
|
|
|
CryptoDevBackend *backend,
|
|
|
|
uint64_t session_id,
|
|
|
|
uint32_t queue_index, Error **errp)
|
|
|
|
{
|
2018-03-01 14:46:30 +01:00
|
|
|
CryptoDevBackendClient *cc =
|
|
|
|
backend->conf.peers.ccs[queue_index];
|
|
|
|
CryptoDevBackendVhost *vhost_crypto;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
vhost_crypto = cryptodev_vhost_user_get_vhost(cc, backend, queue_index);
|
|
|
|
if (vhost_crypto) {
|
|
|
|
struct vhost_dev *dev = &(vhost_crypto->dev);
|
|
|
|
ret = dev->vhost_ops->vhost_crypto_close_session(dev,
|
|
|
|
session_id);
|
|
|
|
if (ret < 0) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
2018-03-01 14:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cryptodev_vhost_user_cleanup(
|
|
|
|
CryptoDevBackend *backend,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
CryptoDevBackendVhostUser *s =
|
|
|
|
CRYPTODEV_BACKEND_VHOST_USER(backend);
|
|
|
|
size_t i;
|
|
|
|
int queues = backend->conf.peers.queues;
|
|
|
|
CryptoDevBackendClient *cc;
|
|
|
|
|
|
|
|
cryptodev_vhost_user_stop(queues, s);
|
|
|
|
|
|
|
|
for (i = 0; i < queues; i++) {
|
|
|
|
cc = backend->conf.peers.ccs[i];
|
|
|
|
if (cc) {
|
|
|
|
cryptodev_backend_free_client(cc);
|
|
|
|
backend->conf.peers.ccs[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2018-05-24 12:33:33 +02:00
|
|
|
|
2019-03-08 15:04:45 +01:00
|
|
|
vhost_user_cleanup(&s->vhost_user);
|
2018-03-01 14:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cryptodev_vhost_user_set_chardev(Object *obj,
|
|
|
|
const char *value, Error **errp)
|
|
|
|
{
|
|
|
|
CryptoDevBackendVhostUser *s =
|
|
|
|
CRYPTODEV_BACKEND_VHOST_USER(obj);
|
|
|
|
|
|
|
|
if (s->opened) {
|
|
|
|
error_setg(errp, QERR_PERMISSION_DENIED);
|
|
|
|
} else {
|
|
|
|
g_free(s->chr_name);
|
|
|
|
s->chr_name = g_strdup(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
cryptodev_vhost_user_get_chardev(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
CryptoDevBackendVhostUser *s =
|
|
|
|
CRYPTODEV_BACKEND_VHOST_USER(obj);
|
|
|
|
Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
|
|
|
|
|
|
|
|
if (chr && chr->label) {
|
|
|
|
return g_strdup(chr->label);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cryptodev_vhost_user_instance_int(Object *obj)
|
|
|
|
{
|
|
|
|
object_property_add_str(obj, "chardev",
|
|
|
|
cryptodev_vhost_user_get_chardev,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 17:29:22 +02:00
|
|
|
cryptodev_vhost_user_set_chardev);
|
2018-03-01 14:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cryptodev_vhost_user_finalize(Object *obj)
|
|
|
|
{
|
|
|
|
CryptoDevBackendVhostUser *s =
|
|
|
|
CRYPTODEV_BACKEND_VHOST_USER(obj);
|
|
|
|
|
|
|
|
qemu_chr_fe_deinit(&s->chr, false);
|
|
|
|
|
|
|
|
g_free(s->chr_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cryptodev_vhost_user_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
|
|
|
|
|
|
|
|
bc->init = cryptodev_vhost_user_init;
|
|
|
|
bc->cleanup = cryptodev_vhost_user_cleanup;
|
|
|
|
bc->create_session = cryptodev_vhost_user_sym_create_session;
|
|
|
|
bc->close_session = cryptodev_vhost_user_sym_close_session;
|
2018-03-01 14:46:30 +01:00
|
|
|
bc->do_sym_op = NULL;
|
2018-03-01 14:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo cryptodev_vhost_user_info = {
|
|
|
|
.name = TYPE_CRYPTODEV_BACKEND_VHOST_USER,
|
|
|
|
.parent = TYPE_CRYPTODEV_BACKEND,
|
|
|
|
.class_init = cryptodev_vhost_user_class_init,
|
|
|
|
.instance_init = cryptodev_vhost_user_instance_int,
|
|
|
|
.instance_finalize = cryptodev_vhost_user_finalize,
|
|
|
|
.instance_size = sizeof(CryptoDevBackendVhostUser),
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
cryptodev_vhost_user_register_types(void)
|
|
|
|
{
|
|
|
|
type_register_static(&cryptodev_vhost_user_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(cryptodev_vhost_user_register_types);
|