qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cryptodev-vhost-user.c (12156B)


      1 /*
      2  * QEMU Cryptodev backend for QEMU cipher APIs
      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
     12  * version 2.1 of the License, or (at your option) any later version.
     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 "qapi/error.h"
     26 #include "qapi/qmp/qerror.h"
     27 #include "qemu/error-report.h"
     28 #include "hw/virtio/vhost-user.h"
     29 #include "standard-headers/linux/virtio_crypto.h"
     30 #include "sysemu/cryptodev-vhost.h"
     31 #include "chardev/char-fe.h"
     32 #include "sysemu/cryptodev-vhost-user.h"
     33 #include "qom/object.h"
     34 
     35 
     36 /**
     37  * @TYPE_CRYPTODEV_BACKEND_VHOST_USER:
     38  * name of backend that uses vhost user server
     39  */
     40 #define TYPE_CRYPTODEV_BACKEND_VHOST_USER "cryptodev-vhost-user"
     41 
     42 OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendVhostUser, CRYPTODEV_BACKEND_VHOST_USER)
     43 
     44 
     45 struct CryptoDevBackendVhostUser {
     46     CryptoDevBackend parent_obj;
     47 
     48     VhostUserState vhost_user;
     49     CharBackend chr;
     50     char *chr_name;
     51     bool opened;
     52     CryptoDevBackendVhost *vhost_crypto[MAX_CRYPTO_QUEUE_NUM];
     53 };
     54 
     55 static int
     56 cryptodev_vhost_user_running(
     57              CryptoDevBackendVhost *crypto)
     58 {
     59     return crypto ? 1 : 0;
     60 }
     61 
     62 CryptoDevBackendVhost *
     63 cryptodev_vhost_user_get_vhost(
     64                          CryptoDevBackendClient *cc,
     65                          CryptoDevBackend *b,
     66                          uint16_t queue)
     67 {
     68     CryptoDevBackendVhostUser *s =
     69                       CRYPTODEV_BACKEND_VHOST_USER(b);
     70     assert(cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER);
     71     assert(queue < MAX_CRYPTO_QUEUE_NUM);
     72 
     73     return s->vhost_crypto[queue];
     74 }
     75 
     76 static void cryptodev_vhost_user_stop(int queues,
     77                           CryptoDevBackendVhostUser *s)
     78 {
     79     size_t i;
     80 
     81     for (i = 0; i < queues; i++) {
     82         if (!cryptodev_vhost_user_running(s->vhost_crypto[i])) {
     83             continue;
     84         }
     85 
     86         cryptodev_vhost_cleanup(s->vhost_crypto[i]);
     87         s->vhost_crypto[i] = NULL;
     88     }
     89 }
     90 
     91 static int
     92 cryptodev_vhost_user_start(int queues,
     93                          CryptoDevBackendVhostUser *s)
     94 {
     95     CryptoDevBackendVhostOptions options;
     96     CryptoDevBackend *b = CRYPTODEV_BACKEND(s);
     97     int max_queues;
     98     size_t i;
     99 
    100     for (i = 0; i < queues; i++) {
    101         if (cryptodev_vhost_user_running(s->vhost_crypto[i])) {
    102             continue;
    103         }
    104 
    105         options.opaque = &s->vhost_user;
    106         options.backend_type = VHOST_BACKEND_TYPE_USER;
    107         options.cc = b->conf.peers.ccs[i];
    108         s->vhost_crypto[i] = cryptodev_vhost_init(&options);
    109         if (!s->vhost_crypto[i]) {
    110             error_report("failed to init vhost_crypto for queue %zu", i);
    111             goto err;
    112         }
    113 
    114         if (i == 0) {
    115             max_queues =
    116               cryptodev_vhost_get_max_queues(s->vhost_crypto[i]);
    117             if (queues > max_queues) {
    118                 error_report("you are asking more queues than supported: %d",
    119                              max_queues);
    120                 goto err;
    121             }
    122         }
    123     }
    124 
    125     return 0;
    126 
    127 err:
    128     cryptodev_vhost_user_stop(i + 1, s);
    129     return -1;
    130 }
    131 
    132 static Chardev *
    133 cryptodev_vhost_claim_chardev(CryptoDevBackendVhostUser *s,
    134                                     Error **errp)
    135 {
    136     Chardev *chr;
    137 
    138     if (s->chr_name == NULL) {
    139         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
    140                    "chardev", "a valid character device");
    141         return NULL;
    142     }
    143 
    144     chr = qemu_chr_find(s->chr_name);
    145     if (chr == NULL) {
    146         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
    147                   "Device '%s' not found", s->chr_name);
    148         return NULL;
    149     }
    150 
    151     return chr;
    152 }
    153 
    154 static void cryptodev_vhost_user_event(void *opaque, QEMUChrEvent event)
    155 {
    156     CryptoDevBackendVhostUser *s = opaque;
    157     CryptoDevBackend *b = CRYPTODEV_BACKEND(s);
    158     int queues = b->conf.peers.queues;
    159 
    160     assert(queues < MAX_CRYPTO_QUEUE_NUM);
    161 
    162     switch (event) {
    163     case CHR_EVENT_OPENED:
    164         if (cryptodev_vhost_user_start(queues, s) < 0) {
    165             exit(1);
    166         }
    167         b->ready = true;
    168         break;
    169     case CHR_EVENT_CLOSED:
    170         b->ready = false;
    171         cryptodev_vhost_user_stop(queues, s);
    172         break;
    173     case CHR_EVENT_BREAK:
    174     case CHR_EVENT_MUX_IN:
    175     case CHR_EVENT_MUX_OUT:
    176         /* Ignore */
    177         break;
    178     }
    179 }
    180 
    181 static void cryptodev_vhost_user_init(
    182              CryptoDevBackend *backend, Error **errp)
    183 {
    184     int queues = backend->conf.peers.queues;
    185     size_t i;
    186     Error *local_err = NULL;
    187     Chardev *chr;
    188     CryptoDevBackendClient *cc;
    189     CryptoDevBackendVhostUser *s =
    190                       CRYPTODEV_BACKEND_VHOST_USER(backend);
    191 
    192     chr = cryptodev_vhost_claim_chardev(s, &local_err);
    193     if (local_err) {
    194         error_propagate(errp, local_err);
    195         return;
    196     }
    197 
    198     s->opened = true;
    199 
    200     for (i = 0; i < queues; i++) {
    201         cc = cryptodev_backend_new_client(
    202                   "cryptodev-vhost-user", NULL);
    203         cc->info_str = g_strdup_printf("cryptodev-vhost-user%zu to %s ",
    204                                        i, chr->label);
    205         cc->queue_index = i;
    206         cc->type = CRYPTODEV_BACKEND_TYPE_VHOST_USER;
    207 
    208         backend->conf.peers.ccs[i] = cc;
    209 
    210         if (i == 0) {
    211             if (!qemu_chr_fe_init(&s->chr, chr, errp)) {
    212                 return;
    213             }
    214         }
    215     }
    216 
    217     if (!vhost_user_init(&s->vhost_user, &s->chr, errp)) {
    218         return;
    219     }
    220 
    221     qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
    222                      cryptodev_vhost_user_event, NULL, s, NULL, true);
    223 
    224     backend->conf.crypto_services =
    225                          1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
    226                          1u << VIRTIO_CRYPTO_SERVICE_HASH |
    227                          1u << VIRTIO_CRYPTO_SERVICE_MAC;
    228     backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
    229     backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
    230 
    231     backend->conf.max_size = UINT64_MAX;
    232     backend->conf.max_cipher_key_len = VHOST_USER_MAX_CIPHER_KEY_LEN;
    233     backend->conf.max_auth_key_len = VHOST_USER_MAX_AUTH_KEY_LEN;
    234 }
    235 
    236 static int64_t cryptodev_vhost_user_sym_create_session(
    237            CryptoDevBackend *backend,
    238            CryptoDevBackendSymSessionInfo *sess_info,
    239            uint32_t queue_index, Error **errp)
    240 {
    241     CryptoDevBackendClient *cc =
    242                    backend->conf.peers.ccs[queue_index];
    243     CryptoDevBackendVhost *vhost_crypto;
    244     uint64_t session_id = 0;
    245     int ret;
    246 
    247     vhost_crypto = cryptodev_vhost_user_get_vhost(cc, backend, queue_index);
    248     if (vhost_crypto) {
    249         struct vhost_dev *dev = &(vhost_crypto->dev);
    250         ret = dev->vhost_ops->vhost_crypto_create_session(dev,
    251                                                           sess_info,
    252                                                           &session_id);
    253         if (ret < 0) {
    254             return -1;
    255         } else {
    256             return session_id;
    257         }
    258     }
    259     return -1;
    260 }
    261 
    262 static int cryptodev_vhost_user_create_session(
    263            CryptoDevBackend *backend,
    264            CryptoDevBackendSessionInfo *sess_info,
    265            uint32_t queue_index,
    266            CryptoDevCompletionFunc cb,
    267            void *opaque)
    268 {
    269     uint32_t op_code = sess_info->op_code;
    270     CryptoDevBackendSymSessionInfo *sym_sess_info;
    271     int64_t ret;
    272     Error *local_error = NULL;
    273     int status;
    274 
    275     switch (op_code) {
    276     case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
    277     case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
    278     case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
    279     case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
    280         sym_sess_info = &sess_info->u.sym_sess_info;
    281         ret = cryptodev_vhost_user_sym_create_session(backend, sym_sess_info,
    282                    queue_index, &local_error);
    283         break;
    284 
    285     default:
    286         error_setg(&local_error, "Unsupported opcode :%" PRIu32 "",
    287                    sess_info->op_code);
    288         return -VIRTIO_CRYPTO_NOTSUPP;
    289     }
    290 
    291     if (local_error) {
    292         error_report_err(local_error);
    293     }
    294     if (ret < 0) {
    295         status = -VIRTIO_CRYPTO_ERR;
    296     } else {
    297         sess_info->session_id = ret;
    298         status = VIRTIO_CRYPTO_OK;
    299     }
    300     if (cb) {
    301         cb(opaque, status);
    302     }
    303     return 0;
    304 }
    305 
    306 static int cryptodev_vhost_user_close_session(
    307            CryptoDevBackend *backend,
    308            uint64_t session_id,
    309            uint32_t queue_index,
    310            CryptoDevCompletionFunc cb,
    311            void *opaque)
    312 {
    313     CryptoDevBackendClient *cc =
    314                   backend->conf.peers.ccs[queue_index];
    315     CryptoDevBackendVhost *vhost_crypto;
    316     int ret = -1, status;
    317 
    318     vhost_crypto = cryptodev_vhost_user_get_vhost(cc, backend, queue_index);
    319     if (vhost_crypto) {
    320         struct vhost_dev *dev = &(vhost_crypto->dev);
    321         ret = dev->vhost_ops->vhost_crypto_close_session(dev,
    322                                                          session_id);
    323         if (ret < 0) {
    324             status = -VIRTIO_CRYPTO_ERR;
    325         } else {
    326             status = VIRTIO_CRYPTO_OK;
    327         }
    328     } else {
    329         status = -VIRTIO_CRYPTO_NOTSUPP;
    330     }
    331     if (cb) {
    332         cb(opaque, status);
    333     }
    334     return 0;
    335 }
    336 
    337 static void cryptodev_vhost_user_cleanup(
    338              CryptoDevBackend *backend,
    339              Error **errp)
    340 {
    341     CryptoDevBackendVhostUser *s =
    342                       CRYPTODEV_BACKEND_VHOST_USER(backend);
    343     size_t i;
    344     int queues = backend->conf.peers.queues;
    345     CryptoDevBackendClient *cc;
    346 
    347     cryptodev_vhost_user_stop(queues, s);
    348 
    349     for (i = 0; i < queues; i++) {
    350         cc = backend->conf.peers.ccs[i];
    351         if (cc) {
    352             cryptodev_backend_free_client(cc);
    353             backend->conf.peers.ccs[i] = NULL;
    354         }
    355     }
    356 
    357     vhost_user_cleanup(&s->vhost_user);
    358 }
    359 
    360 static void cryptodev_vhost_user_set_chardev(Object *obj,
    361                                     const char *value, Error **errp)
    362 {
    363     CryptoDevBackendVhostUser *s =
    364                       CRYPTODEV_BACKEND_VHOST_USER(obj);
    365 
    366     if (s->opened) {
    367         error_setg(errp, "Property 'chardev' can no longer be set");
    368     } else {
    369         g_free(s->chr_name);
    370         s->chr_name = g_strdup(value);
    371     }
    372 }
    373 
    374 static char *
    375 cryptodev_vhost_user_get_chardev(Object *obj, Error **errp)
    376 {
    377     CryptoDevBackendVhostUser *s =
    378                       CRYPTODEV_BACKEND_VHOST_USER(obj);
    379     Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
    380 
    381     if (chr && chr->label) {
    382         return g_strdup(chr->label);
    383     }
    384 
    385     return NULL;
    386 }
    387 
    388 static void cryptodev_vhost_user_finalize(Object *obj)
    389 {
    390     CryptoDevBackendVhostUser *s =
    391                       CRYPTODEV_BACKEND_VHOST_USER(obj);
    392 
    393     qemu_chr_fe_deinit(&s->chr, false);
    394 
    395     g_free(s->chr_name);
    396 }
    397 
    398 static void
    399 cryptodev_vhost_user_class_init(ObjectClass *oc, void *data)
    400 {
    401     CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
    402 
    403     bc->init = cryptodev_vhost_user_init;
    404     bc->cleanup = cryptodev_vhost_user_cleanup;
    405     bc->create_session = cryptodev_vhost_user_create_session;
    406     bc->close_session = cryptodev_vhost_user_close_session;
    407     bc->do_op = NULL;
    408 
    409     object_class_property_add_str(oc, "chardev",
    410                                   cryptodev_vhost_user_get_chardev,
    411                                   cryptodev_vhost_user_set_chardev);
    412 
    413 }
    414 
    415 static const TypeInfo cryptodev_vhost_user_info = {
    416     .name = TYPE_CRYPTODEV_BACKEND_VHOST_USER,
    417     .parent = TYPE_CRYPTODEV_BACKEND,
    418     .class_init = cryptodev_vhost_user_class_init,
    419     .instance_finalize = cryptodev_vhost_user_finalize,
    420     .instance_size = sizeof(CryptoDevBackendVhostUser),
    421 };
    422 
    423 static void
    424 cryptodev_vhost_user_register_types(void)
    425 {
    426     type_register_static(&cryptodev_vhost_user_info);
    427 }
    428 
    429 type_init(cryptodev_vhost_user_register_types);