All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Longpeng (Mike)" <longpeng2@huawei.com>
To: Halil Pasic <pasic@linux.vnet.ibm.com>
Cc: qemu-devel@nongnu.org, virtio-dev@lists.oasis-open.org,
	weidong.huang@huawei.com, mst@redhat.com, jasowang@redhat.com,
	john.griffin@intel.com, Varun.Sethi@freescale.com,
	denglingli@chinamobile.com, arei.gonglei@hotmail.com,
	agraf@suse.de, arei.gonglei@huawei.com, vincent.jardin@6wind.com,
	Ola.Liljedahl@arm.com, luonengjun@huawei.com, xin.zeng@intel.com,
	liang.j.ma@intel.com, stefanha@redhat.com,
	Jani.Kokkonen@huawei.com, brian.a.keating@intel.com,
	wangxinxin.wang@huawei.com, cohuck@redhat.com,
	mike.caraman@nxp.com
Subject: Re: [Qemu-devel] [virtio-dev] Re: [RFC 0/8] virtio-crypto: add multiplexing mode support
Date: Thu, 14 Sep 2017 08:58:33 +0800	[thread overview]
Message-ID: <59B9D439.10807@huawei.com> (raw)
In-Reply-To: <2d8ae3d3-438b-da84-4959-cf63f4f4ce99@linux.vnet.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 2732 bytes --]



On 2017/9/14 2:14, Halil Pasic wrote:

> 
> 
> On 09/11/2017 03:10 AM, Longpeng(Mike) wrote:
>> *NOTE*
>> The code realization is based on the latest virtio crypto spec:
>>  [PATCH v19 0/2] virtio-crypto: virtio crypto device specification
>>    https://lists.nongnu.org/archive/html/qemu-devel/2017-08/msg05217.html
>>
>> In session mode, the process of create/close a session
>> makes we have a least one full round-trip cost from guest to host to guest
>> to be able to send any data for symmetric algorithms. It gets ourself into
>> synchronization troubles in some scenarios like a web server handling lots
>> of small requests whose algorithms and keys are different.
>>
>> We can support one-blob request (no sessions) as well for symmetric
>> algorithms, including HASH, MAC services. The benefit is obvious for
>> HASH service because it's usually a one-blob operation.
>>
> 
> Hi!
> 
> I've just started looking at this. Patch #1 modifies linux/virtio_crypto.h
> which if I compare with the (almost) latest linux master is different. Thus
> I would expect a corresponding kernel patch set too, but I haven't received
> one, nor did I find a reference in the cover letter.
> 
> I think if I want to test the new features I need the kernel counter-part
> too, or?
> 
> Could you point me to the kernel counterpart?
> 


Hi Halil,

We haven't implemented the kernel frontend part yet, but there's a testcase
based on qtest, you can use it.

Please see the attachment.

-- 
Regards,
Longpeng(Mike)

> Regards,
> Halil
> 
> 
>> Gonglei (3):
>>   virtio-crypto: add stateless crypto request handler
>>   cryptodev: extract one util function
>>   virtio-crypto: add host feature bits support
>>
>> Longpeng(Mike) (5):
>>   virtio-crypto: add new definations for multiplexing mode
>>   virtio-crypto: add session creation logic for mux mode
>>   virtio-crypto: add dataq operation logic for mux mode
>>   cryptodev: add stateless mode cipher support
>>   cryptodev-builtin: add stateless cipher support
>>
>>  backends/cryptodev-builtin.c                   | 189 ++++++++---
>>  backends/cryptodev.c                           |  21 ++
>>  hw/virtio/virtio-crypto.c                      | 433 +++++++++++++++++++++++--
>>  include/hw/virtio/virtio-crypto.h              |   2 +
>>  include/standard-headers/linux/virtio_crypto.h | 182 ++++++++++-
>>  include/sysemu/cryptodev.h                     |  21 ++
>>  6 files changed, 774 insertions(+), 74 deletions(-)
>>
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
> For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org
> 
> 
> .
> 


-- 
Regards,
Longpeng(Mike)

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: testcase.patch --]
[-- Type: text/plain; charset="gb18030"; name="testcase.patch", Size: 24223 bytes --]

From 259359700b1847cd66f9c3e04a86a14546f6f0e0 Mon Sep 17 00:00:00 2001
From: Gonglei <arei.gonglei@huawei.com>
Date: Mon, 8 May 2017 13:42:53 +0800
Subject: [PATCH] qtest: emulate virtio crypto as a legacy device for
 experiment

Because the current qtest framework do not support virtio-1
or latter devices. For experimental purpose,
let's emulate the virtio crypto device as a legacy virtio
device by default. Using 0x1014 as virtio crypto pci device ID
because virtio crypto ID is 20 (0x14).

Signed-off-by: Gonglei <arei.gonglei@huawei.com>

virtio-crypto-test: add qtest case for virtio-crypto

We can simply test the functions of virtio crypto
device, including session creation, session closing,
cipher encryption and decryption.

Quick usage:
 # make tests/virtio-crypto-test && ./tests/virtio-crypto-test
  CC    tests/virtio-crypto-test.o
  LINK  tests/virtio-crypto-test
/virtio/crypto/cbc(aes-128-session-mode): OK
/virtio/crypto/cbc(aes-128-stateless-mode): OK

Signed-off-by: Gonglei <arei.gonglei@huawei.com>
[rebase on the v19 spec]
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
---
 docs/specs/pci-ids.txt        |   2 +
 hw/virtio/virtio-crypto-pci.c |   4 +-
 include/hw/pci/pci.h          |   2 +
 tests/Makefile.include        |   3 +
 tests/virtio-crypto-test.c    | 600 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 610 insertions(+), 1 deletion(-)
 create mode 100644 tests/virtio-crypto-test.c

diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt
index bb99a02..61877b7 100755
--- a/docs/specs/pci-ids.txt
+++ b/docs/specs/pci-ids.txt
@@ -22,6 +22,7 @@ maintained as part of the virtio specification.
 1af4:1004  SCSI host bus adapter device (legacy)
 1af4:1005  entropy generator device (legacy)
 1af4:1009  9p filesystem device (legacy)
+1af4:1014  crypto device (legacy)
 
 1af4:1041  network device (modern)
 1af4:1042  block device (modern)
@@ -32,6 +33,7 @@ maintained as part of the virtio specification.
 1af4:1049  9p filesystem device (modern)
 1af4:1050  virtio gpu device (modern)
 1af4:1052  virtio input device (modern)
+1af4:1054  crypto device (modern)
 
 1af4:10f0  Available for experimental usage without registration.  Must get
    to      official ID when the code leaves the test lab (i.e. when seeking
diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c
index bf64996..66a2966 100755
--- a/hw/virtio/virtio-crypto-pci.c
+++ b/hw/virtio/virtio-crypto-pci.c
@@ -37,7 +37,6 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
     }
 
     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
-    virtio_pci_force_virtio_1(vpci_dev);
     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
     object_property_set_link(OBJECT(vcrypto),
                  OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev",
@@ -53,6 +52,9 @@ static void virtio_crypto_pci_class_init(ObjectClass *klass, void *data)
     k->realize = virtio_crypto_pci_realize;
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
     dc->props = virtio_crypto_pci_properties;
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CRYPTO;
+    pcidev_k->revision = 0;
     pcidev_k->class_id = PCI_CLASS_OTHERS;
 }
 
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index e598b09..ae9327c 100755
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -83,6 +83,8 @@
 #define PCI_DEVICE_ID_VIRTIO_RNG         0x1005
 #define PCI_DEVICE_ID_VIRTIO_9P          0x1009
 #define PCI_DEVICE_ID_VIRTIO_VSOCK       0x1012
+#define PCI_DEVICE_ID_VIRTIO_CRYPTO      0x1014
+
 
 #define PCI_VENDOR_ID_REDHAT             0x1b36
 #define PCI_DEVICE_ID_REDHAT_BRIDGE      0x0001
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 37c1bed..9b6c131 100755
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -192,6 +192,8 @@ check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/char/virtio-serial-bus.c
 check-qtest-virtio-y += $(check-qtest-virtioserial-y)
 gcov-files-virtio-y += $(gcov-files-virtioserial-y)
+check-qtest-virtio-y += tests/virtio-crypto-test$(EXESUF)
+gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-crypto.c
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 gcov-files-pci-y += hw/net/e1000.c
@@ -753,6 +755,7 @@ tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
 tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o $(libqos-virtio-obj-y)
 tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o
 tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o
+tests/virtio-crypto-test$(EXESUF): tests/virtio-crypto-test.o $(libqos-virtio-obj-y)
 tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
 tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
diff --git a/tests/virtio-crypto-test.c b/tests/virtio-crypto-test.c
new file mode 100644
index 0000000..8825f1f
--- /dev/null
+++ b/tests/virtio-crypto-test.c
@@ -0,0 +1,600 @@
+/*
+ * QTest testcase for VirtIO Crypto Device
+ *
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Gonglei <arei.gonglei@huawei.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdlib.h>
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+#include "libqos/virtio-mmio.h"
+#include "libqos/pci-pc.h"
+#include "libqos/malloc.h"
+#include "libqos/malloc-pc.h"
+#include "libqos/malloc-generic.h"
+#include "qemu/bswap.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_config.h"
+#include "standard-headers/linux/virtio_ring.h"
+#include "standard-headers/linux/virtio_crypto.h"
+#include "standard-headers/linux/virtio_pci.h"
+
+#define QVIRTIO_CRYPTO_TIMEOUT_US  (30 * 1000 * 1000)
+
+#define PCI_SLOT_HP             0x06
+#define PCI_SLOT                0x04
+#define PCI_FN                  0x00
+
+/*
+ * VirtIOCryptoCipherTestData:  structure to describe a cipher test
+ * @key:    A pointer to a key used by the test
+ * @key_len:    The length of @key
+ * @iv:     A pointer to the IV/Counter used by the test
+ * @iv_len: The length of @iv
+ * @input:  A pointer to data used as input
+ * @ilen    The length of data in @input
+ * @output: A pointer to what the test need to produce
+ * @olen:   The length of data in @output
+ * @algo:   The type of algorithm, refer to VIRTIO_CRYPTO_CIPHER_AES_*
+ */
+typedef struct VirtIOCryptoCipherTestData {
+    const char *path;
+    unsigned short algo;
+    const char *key;
+    const char *iv;
+    const char *input;
+    const char *output;
+    unsigned char key_len;
+    unsigned char iv_len;
+    unsigned short ilen;
+    unsigned short olen;
+    bool is_statelss_mode;
+} VirtIOCryptoCipherTestData;
+
+
+static VirtIOCryptoCipherTestData cipher_test_data[] = {
+    { /* From RFC 3602 */
+        .path = "/virtio/crypto/cbc(aes-128-session-mode)",
+        .algo = VIRTIO_CRYPTO_CIPHER_AES_CBC,
+        .key  = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+                "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+        .key_len   = 16,
+        .iv = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+              "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+        .iv_len = 16,
+        .input  = "Single block msg",
+        .ilen   = 16,
+        .output = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
+                  "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
+        .olen   = 16,
+        .is_statelss_mode = false,
+    },
+    { /* From RFC 3602 */
+        .path = "/virtio/crypto/cbc(aes-128-stateless-mode)",
+        .algo = VIRTIO_CRYPTO_CIPHER_AES_CBC,
+        .key  = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+                "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+        .key_len   = 16,
+        .iv = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+              "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+        .iv_len = 16,
+        .input  = "Single block msg",
+        .ilen   = 16,
+        .output = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
+                  "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
+        .olen   = 16,
+        .is_statelss_mode = true,
+    },
+};
+
+static QPCIBus *virtio_crypto_test_start(void)
+{
+    char *cmdline;
+
+    cmdline = g_strdup_printf(
+               "-object cryptodev-backend-builtin,id=cryptodev0 "
+               "-device virtio-crypto-pci,id=crypto0,"
+               "cryptodev=cryptodev0");
+
+    qtest_start(cmdline);
+    g_free(cmdline);
+
+    return qpci_init_pc(NULL);
+}
+
+static void test_end(void)
+{
+    qtest_end();
+}
+
+static QVirtioPCIDevice *virtio_crypto_pci_init(QPCIBus *bus, int slot)
+{
+    QVirtioPCIDevice *dev;
+
+    dev = qvirtio_pci_device_find(bus, VIRTIO_ID_CRYPTO);
+    g_assert(dev != NULL);
+    g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_CRYPTO);
+
+    qvirtio_pci_device_enable(dev);
+    qvirtio_reset(&dev->vdev);
+    qvirtio_set_acknowledge(&dev->vdev);
+    qvirtio_set_driver(&dev->vdev);
+
+    return dev;
+}
+
+static uint64_t
+virtio_crypto_ctrl_request(QGuestAllocator *alloc,
+                           struct virtio_crypto_op_ctrl_req *req)
+{
+    uint64_t addr;
+
+    addr = guest_alloc(alloc, sizeof(*req));
+
+    memwrite(addr, req, sizeof(*req));
+
+    return addr;
+}
+
+static uint64_t
+virtio_crypto_data_request(QGuestAllocator *alloc,
+                           struct virtio_crypto_op_data_req *req)
+{
+    uint64_t addr;
+
+    addr = guest_alloc(alloc, sizeof(*req));
+
+    memwrite(addr, req, sizeof(*req));
+
+    return addr;
+}
+
+static void
+virtio_crypto_driver_init(QVirtioDevice *dev)
+{
+    /* Read configure space to get  supported crypto services */
+
+    qvirtio_set_driver_ok(dev);
+}
+
+static uint64_t
+virtio_crypto_create_session(QVirtioDevice *dev,
+            QGuestAllocator *alloc, QVirtQueue *vq,
+            VirtIOCryptoCipherTestData *data,
+            int encrypt)
+{
+    uint32_t free_head;
+    struct virtio_crypto_op_ctrl_req ctrl;
+    struct virtio_crypto_session_input input;
+    uint32_t key_len = data->key_len;
+    uint64_t req_addr;
+    uint64_t key_addr, input_addr; /* cipher key guest physical address */
+    uint64_t session_id;
+    QVRingIndirectDesc *indirect;
+
+    /* Create an encryption session */
+    ctrl.header.opcode = VIRTIO_CRYPTO_CIPHER_CREATE_SESSION;
+    ctrl.header.algo = data->algo;
+    /* Set the default dataqueue id to 0 */
+    ctrl.header.queue_id = 0;
+
+    /* Pad cipher's parameters */
+    ctrl.u.sym_create_session.op_type = VIRTIO_CRYPTO_SYM_OP_CIPHER;
+    ctrl.u.sym_create_session.u.cipher.para.algo = ctrl.header.algo;
+    ctrl.u.sym_create_session.u.cipher.para.keylen = key_len;
+    if (encrypt) {
+        ctrl.u.sym_create_session.u.cipher.para.op = VIRTIO_CRYPTO_OP_ENCRYPT;
+    } else {
+        ctrl.u.sym_create_session.u.cipher.para.op = VIRTIO_CRYPTO_OP_DECRYPT;
+    }
+
+    req_addr = virtio_crypto_ctrl_request(alloc, &ctrl);
+
+    /* Pad cipher's output data */
+    key_addr = guest_alloc(alloc, key_len);
+    memwrite(key_addr, data->key, key_len);
+
+    input.status = VIRTIO_CRYPTO_ERR;
+    input_addr = guest_alloc(alloc, sizeof(input));
+    memwrite(input_addr, &input, sizeof(input));
+
+    indirect = qvring_indirect_desc_setup(dev, alloc, 3);
+    qvring_indirect_desc_add(indirect, req_addr, sizeof(ctrl), false);
+    qvring_indirect_desc_add(indirect, key_addr, key_len, false);
+    qvring_indirect_desc_add(indirect, input_addr, sizeof(input), true);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+
+    qvirtqueue_kick(dev, vq, free_head);
+
+    qvirtio_wait_queue_isr(dev, vq, QVIRTIO_CRYPTO_TIMEOUT_US);
+
+    /* calculate the offset of input data */
+
+    memread(input_addr, &input, sizeof(input));
+
+    /* Verify the result */
+    g_assert_cmpint(input.status, ==, VIRTIO_CRYPTO_OK);
+
+    session_id = input.session_id;
+
+    g_free(indirect);
+    guest_free(alloc, input_addr);
+    guest_free(alloc, key_addr);
+    guest_free(alloc, req_addr);
+
+    return session_id;
+}
+
+static void
+virtio_crypto_close_session(QVirtioDevice *dev,
+            QGuestAllocator *alloc, QVirtQueue *vq,
+            uint64_t session_id)
+{
+    uint32_t free_head;
+    struct virtio_crypto_op_ctrl_req ctrl;
+    uint64_t req_addr, status_addr;
+    uint8_t status;
+    QVRingIndirectDesc *indirect;
+
+    /* Create an encryption session */
+    ctrl.header.opcode = VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION;
+    /* Set the default dataqueue id to 0 */
+    ctrl.header.queue_id = 0;
+
+    ctrl.u.destroy_session.session_id = session_id;
+
+    req_addr = virtio_crypto_ctrl_request(alloc, &ctrl);
+
+    status_addr = guest_alloc(alloc, sizeof(status));
+    writel(status_addr, VIRTIO_CRYPTO_ERR);
+
+    indirect = qvring_indirect_desc_setup(dev, alloc, 2);
+    qvring_indirect_desc_add(indirect, req_addr, sizeof(ctrl), false);
+    qvring_indirect_desc_add(indirect, status_addr, sizeof(status), true);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+
+    qvirtqueue_kick(dev, vq, free_head);
+
+    qvirtio_wait_queue_isr(dev, vq, QVIRTIO_CRYPTO_TIMEOUT_US);
+
+    /* Verify the result */
+    status = readl(status_addr);
+    g_assert_cmpint(status, ==, VIRTIO_CRYPTO_OK);
+
+    g_free(indirect);
+    guest_free(alloc, req_addr);
+    guest_free(alloc, status_addr);
+}
+
+
+static void
+virtio_crypto_test_cipher_session_mode(QVirtioDevice *dev,
+            QGuestAllocator *alloc, QVirtQueue *ctrlq,
+            QVirtQueue *vq, VirtIOCryptoCipherTestData *data,
+            int encrypt)
+{
+    uint32_t free_head;
+    struct virtio_crypto_op_data_req req;
+    uint64_t req_addr, status_addr;
+    uint64_t iv_addr = 0, src_addr, dst_addr;
+    uint64_t session_id;
+    char *output;
+    uint32_t src_len, dst_len;
+    uint8_t status;
+    QVRingIndirectDesc *indirect;
+    uint8_t entry_num;
+
+    /* Create a session */
+    session_id = virtio_crypto_create_session(dev, alloc,
+                                             ctrlq, data, encrypt);
+
+    /* Head of operation */
+    req.header.session_id = session_id;
+    if (encrypt) {
+        req.header.opcode = VIRTIO_CRYPTO_CIPHER_ENCRYPT;
+    } else {
+        req.header.opcode = VIRTIO_CRYPTO_CIPHER_DECRYPT;
+    }
+
+    req.u.sym_req.op_type = VIRTIO_CRYPTO_SYM_OP_CIPHER;
+    req.u.sym_req.u.cipher.para.iv_len = data->iv_len;
+    req.u.sym_req.u.cipher.para.src_data_len = data->ilen;
+    req.u.sym_req.u.cipher.para.dst_data_len = data->olen;
+
+    req_addr = virtio_crypto_data_request(alloc, &req);
+
+    /* IV */
+    if (data->iv_len > 0) {
+        iv_addr = guest_alloc(alloc, data->iv_len);
+        memwrite(iv_addr, data->iv, data->iv_len);
+
+        /* header + iv + src + dst + status */
+        entry_num = 5;
+    } else {
+        /* header + src + dst + status */
+        entry_num = 4;
+    }
+
+    if (encrypt) {
+        src_len = data->ilen;
+        dst_len = data->olen;
+        /* Source data is the input data which is a single buffer */
+        src_addr = guest_alloc(alloc, src_len);
+        memwrite(src_addr, data->input, src_len);
+    } else {
+        src_len = data->olen;
+        dst_len = data->ilen;
+        /* Source data is the output data which is a single buffer */
+        src_addr = guest_alloc(alloc, src_len);
+        memwrite(src_addr, data->output, src_len);
+    }
+
+    dst_addr = guest_alloc(alloc, dst_len);
+
+    status_addr = guest_alloc(alloc, sizeof(status));
+    writel(status_addr, VIRTIO_CRYPTO_ERR);
+
+    /* Allocate descripto table entries */
+    indirect = qvring_indirect_desc_setup(dev, alloc, entry_num);
+    qvring_indirect_desc_add(indirect, req_addr, sizeof(req), false);
+    if (data->iv_len > 0) {
+        qvring_indirect_desc_add(indirect, iv_addr, data->iv_len, false);
+    }
+    qvring_indirect_desc_add(indirect, src_addr, src_len, false);
+    qvring_indirect_desc_add(indirect, dst_addr, dst_len, true);
+    qvring_indirect_desc_add(indirect, status_addr, sizeof(status), true);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+
+    qvirtqueue_kick(dev, vq, free_head);
+
+    qvirtio_wait_queue_isr(dev, vq, QVIRTIO_CRYPTO_TIMEOUT_US);
+
+    /* Verify the result */
+    status = readl(status_addr);
+    g_assert_cmpint(status, ==, VIRTIO_CRYPTO_OK);
+
+    output = g_malloc0(dst_len);
+    memread(dst_addr, output, dst_len);
+    if (encrypt) {
+        g_assert_cmpstr(output, ==, data->output);
+    } else {
+        g_assert_cmpstr(output, ==, data->input);
+    }
+    g_free(output);
+
+    g_free(indirect);
+
+    if (data->iv_len > 0) {
+        guest_free(alloc, iv_addr);
+    }
+    guest_free(alloc, src_addr);
+    guest_free(alloc, dst_addr);
+    guest_free(alloc, req_addr);
+    guest_free(alloc, status_addr);
+
+    /* Close the session */
+    virtio_crypto_close_session(dev, alloc, ctrlq, session_id);
+}
+
+static void
+virtio_crypto_test_cipher_stateless_mode(QVirtioDevice *dev,
+            QGuestAllocator *alloc,
+            QVirtQueue *vq, VirtIOCryptoCipherTestData *data,
+            int encrypt)
+{
+    uint32_t free_head;
+    struct virtio_crypto_op_data_req_mux req;
+    struct virtio_crypto_sym_data_req_stateless para;
+    uint64_t req_addr, para_addr, status_addr;
+    uint64_t iv_addr = 0, src_addr, dst_addr, key_addr;
+    char *output;
+    uint32_t src_len, dst_len;
+    uint8_t status;
+    QVRingIndirectDesc *indirect;
+    uint8_t entry_num;
+
+    /* Head of operation */
+    req.header.flag = 0;
+    if (encrypt) {
+        req.header.opcode = VIRTIO_CRYPTO_CIPHER_ENCRYPT;
+        para.u.cipher.para.sess_para.op = VIRTIO_CRYPTO_OP_ENCRYPT;
+    } else {
+        req.header.opcode = VIRTIO_CRYPTO_CIPHER_DECRYPT;
+        para.u.cipher.para.sess_para.op = VIRTIO_CRYPTO_OP_DECRYPT;
+    }
+
+    para.op_type = VIRTIO_CRYPTO_SYM_OP_CIPHER;
+    para.u.cipher.para.sess_para.algo = data->algo;
+    para.u.cipher.para.sess_para.keylen = data->key_len;
+    para.u.cipher.para.iv_len = data->iv_len;
+    para.u.cipher.para.src_data_len = data->ilen;
+    para.u.cipher.para.dst_data_len = data->olen;
+
+    req_addr = guest_alloc(alloc, sizeof(req));
+    memwrite(req_addr, &req, sizeof(req));
+
+    para_addr = guest_alloc(alloc, sizeof(para));
+    memwrite(para_addr, &para, sizeof(para));
+
+    g_assert(data->key_len > 0);
+    key_addr = guest_alloc(alloc, data->key_len);
+    memwrite(key_addr, data->key, data->key_len);
+
+    /* IV */
+    if (data->iv_len > 0) {
+        iv_addr = guest_alloc(alloc, data->iv_len);
+        memwrite(iv_addr, data->iv, data->iv_len);
+
+        /* header + key + iv + src + dst + status */
+        entry_num = 7;
+    } else {
+        /* header + key + src + dst + status */
+        entry_num = 6;
+    }
+
+    if (encrypt) {
+        src_len = data->ilen;
+        dst_len = data->olen;
+        /* Source data is the input data which is a single buffer */
+        src_addr = guest_alloc(alloc, src_len);
+        memwrite(src_addr, data->input, src_len);
+    } else {
+        src_len = data->olen;
+        dst_len = data->ilen;
+        /* Source data is the output data which is a single buffer */
+        src_addr = guest_alloc(alloc, src_len);
+        memwrite(src_addr, data->output, src_len);
+    }
+
+    dst_addr = guest_alloc(alloc, dst_len);
+
+    status_addr = guest_alloc(alloc, sizeof(status));
+    writel(status_addr, VIRTIO_CRYPTO_ERR);
+
+    /* Allocate desc table entries */
+    indirect = qvring_indirect_desc_setup(dev, alloc, entry_num);
+    qvring_indirect_desc_add(indirect, req_addr, sizeof(req), false);
+    qvring_indirect_desc_add(indirect, para_addr, sizeof(para), false);
+    qvring_indirect_desc_add(indirect, key_addr, data->key_len, false);
+    if (data->iv_len > 0) {
+        qvring_indirect_desc_add(indirect, iv_addr, data->iv_len, false);
+    }
+    qvring_indirect_desc_add(indirect, src_addr, src_len, false);
+    qvring_indirect_desc_add(indirect, dst_addr, dst_len, true);
+    qvring_indirect_desc_add(indirect, status_addr, sizeof(status), true);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+
+    qvirtqueue_kick(dev, vq, free_head);
+
+    qvirtio_wait_queue_isr(dev, vq, QVIRTIO_CRYPTO_TIMEOUT_US);
+
+    /* Verify the result */
+    status = readl(status_addr);
+    g_assert_cmpint(status, ==, VIRTIO_CRYPTO_OK);
+
+    output = g_malloc0(dst_len);
+    memread(dst_addr, output, dst_len);
+    if (encrypt) {
+        g_assert_cmpstr(output, ==, data->output);
+    } else {
+        g_assert_cmpstr(output, ==, data->input);
+    }
+    g_free(output);
+
+    g_free(indirect);
+    guest_free(alloc, key_addr);
+    if (data->iv_len > 0) {
+        guest_free(alloc, iv_addr);
+    }
+    guest_free(alloc, src_addr);
+    guest_free(alloc, dst_addr);
+    guest_free(alloc, para_addr);
+    guest_free(alloc, req_addr);
+    guest_free(alloc, status_addr);
+}
+
+static void
+virtio_crypto_test_cipher(QVirtioDevice *dev,
+            QGuestAllocator *alloc, QVirtQueue *ctrlq,
+            QVirtQueue *dataq, VirtIOCryptoCipherTestData *data,
+            int encrypt)
+{
+    if (!data->is_statelss_mode) {
+        virtio_crypto_test_cipher_session_mode(dev, alloc,
+            ctrlq, dataq, data, encrypt);
+    } else {
+        virtio_crypto_test_cipher_stateless_mode(dev, alloc,
+            dataq, data, encrypt);
+    }
+}
+
+static void virtio_crypto_pci_basic(void *opaque)
+{
+    VirtIOCryptoCipherTestData *test_data = opaque;
+    QVirtioPCIDevice *dev;
+    QPCIBus *bus;
+    QGuestAllocator *alloc;
+    QVirtQueuePCI *dataq, *controlq;
+    uint32_t features;
+
+    bus = virtio_crypto_test_start();
+    dev = virtio_crypto_pci_init(bus, PCI_SLOT);
+
+    alloc = pc_alloc_init();
+
+    features = qvirtio_get_features(&dev->vdev);
+    g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
+
+    if (!test_data->is_statelss_mode) {
+        features = features & ~(QVIRTIO_F_BAD_FEATURE |
+                                (1u << VIRTIO_RING_F_EVENT_IDX |
+                                1u << VIRTIO_CRYPTO_F_MUX_MODE |
+                                1u << VIRTIO_CRYPTO_F_CIPHER_STATELESS_MODE));
+    } else {
+        features = features & ~(QVIRTIO_F_BAD_FEATURE |
+                                (1u << VIRTIO_RING_F_EVENT_IDX));
+    }
+    qvirtio_set_features(&dev->vdev, features);
+
+    dataq = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev,
+                                           alloc, 0);
+    controlq = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev,
+                                           alloc, 1);
+
+    virtio_crypto_driver_init(&dev->vdev);
+
+    /* Step 1: Encryption */
+    virtio_crypto_test_cipher(&dev->vdev, alloc,
+                              &controlq->vq, &dataq->vq,
+                              test_data, 1);
+    /* Step 2: Decryption */
+    virtio_crypto_test_cipher(&dev->vdev, alloc,
+                              &controlq->vq, &dataq->vq,
+                              test_data, 0);
+
+    /* End test */
+    guest_free(alloc, dataq->vq.desc);
+    guest_free(alloc, controlq->vq.desc);
+    pc_alloc_uninit(alloc);
+    qvirtio_pci_device_disable(dev);
+    g_free(dev);
+    qpci_free_pc(bus);
+    test_end();
+}
+
+int main(int argc, char **argv)
+{
+    const char *qemu;
+    const char *arch;
+    int i, ret;
+
+    qemu = getenv("QTEST_QEMU_BINARY");
+    if (qemu == NULL) {
+        ret = setenv("QTEST_QEMU_BINARY",
+                     "x86_64-softmmu/qemu-system-x86_64", 0);
+        g_assert(ret == 0);
+    }
+
+    arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        for (i = 0; i < G_N_ELEMENTS(cipher_test_data); i++) {
+            g_test_add_data_func(cipher_test_data[i].path,
+                                 (void *)&cipher_test_data[i],
+                                 (GTestDataFunc)virtio_crypto_pci_basic);
+        }
+    }
+
+    return g_test_run();
+}
-- 
1.8.3.1


WARNING: multiple messages have this Message-ID (diff)
From: "Longpeng (Mike)" <longpeng2@huawei.com>
To: Halil Pasic <pasic@linux.vnet.ibm.com>
Cc: qemu-devel@nongnu.org, virtio-dev@lists.oasis-open.org,
	weidong.huang@huawei.com, mst@redhat.com, jasowang@redhat.com,
	john.griffin@intel.com, Varun.Sethi@freescale.com,
	denglingli@chinamobile.com, arei.gonglei@hotmail.com,
	agraf@suse.de, arei.gonglei@huawei.com, vincent.jardin@6wind.com,
	Ola.Liljedahl@arm.com, luonengjun@huawei.com, xin.zeng@intel.com,
	liang.j.ma@intel.com, stefanha@redhat.com,
	Jani.Kokkonen@huawei.com, brian.a.keating@intel.com,
	wangxinxin.wang@huawei.com, cohuck@redhat.com,
	mike.caraman@nxp.com
Subject: Re: [virtio-dev] Re: [Qemu-devel] [RFC 0/8] virtio-crypto: add multiplexing mode support
Date: Thu, 14 Sep 2017 08:58:33 +0800	[thread overview]
Message-ID: <59B9D439.10807@huawei.com> (raw)
In-Reply-To: <2d8ae3d3-438b-da84-4959-cf63f4f4ce99@linux.vnet.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 2732 bytes --]



On 2017/9/14 2:14, Halil Pasic wrote:

> 
> 
> On 09/11/2017 03:10 AM, Longpeng(Mike) wrote:
>> *NOTE*
>> The code realization is based on the latest virtio crypto spec:
>>  [PATCH v19 0/2] virtio-crypto: virtio crypto device specification
>>    https://lists.nongnu.org/archive/html/qemu-devel/2017-08/msg05217.html
>>
>> In session mode, the process of create/close a session
>> makes we have a least one full round-trip cost from guest to host to guest
>> to be able to send any data for symmetric algorithms. It gets ourself into
>> synchronization troubles in some scenarios like a web server handling lots
>> of small requests whose algorithms and keys are different.
>>
>> We can support one-blob request (no sessions) as well for symmetric
>> algorithms, including HASH, MAC services. The benefit is obvious for
>> HASH service because it's usually a one-blob operation.
>>
> 
> Hi!
> 
> I've just started looking at this. Patch #1 modifies linux/virtio_crypto.h
> which if I compare with the (almost) latest linux master is different. Thus
> I would expect a corresponding kernel patch set too, but I haven't received
> one, nor did I find a reference in the cover letter.
> 
> I think if I want to test the new features I need the kernel counter-part
> too, or?
> 
> Could you point me to the kernel counterpart?
> 


Hi Halil,

We haven't implemented the kernel frontend part yet, but there's a testcase
based on qtest, you can use it.

Please see the attachment.

-- 
Regards,
Longpeng(Mike)

> Regards,
> Halil
> 
> 
>> Gonglei (3):
>>   virtio-crypto: add stateless crypto request handler
>>   cryptodev: extract one util function
>>   virtio-crypto: add host feature bits support
>>
>> Longpeng(Mike) (5):
>>   virtio-crypto: add new definations for multiplexing mode
>>   virtio-crypto: add session creation logic for mux mode
>>   virtio-crypto: add dataq operation logic for mux mode
>>   cryptodev: add stateless mode cipher support
>>   cryptodev-builtin: add stateless cipher support
>>
>>  backends/cryptodev-builtin.c                   | 189 ++++++++---
>>  backends/cryptodev.c                           |  21 ++
>>  hw/virtio/virtio-crypto.c                      | 433 +++++++++++++++++++++++--
>>  include/hw/virtio/virtio-crypto.h              |   2 +
>>  include/standard-headers/linux/virtio_crypto.h | 182 ++++++++++-
>>  include/sysemu/cryptodev.h                     |  21 ++
>>  6 files changed, 774 insertions(+), 74 deletions(-)
>>
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
> For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org
> 
> 
> .
> 


-- 
Regards,
Longpeng(Mike)

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: testcase.patch --]
[-- Type: text/plain; charset="gb18030"; name="testcase.patch", Size: 24223 bytes --]

From 259359700b1847cd66f9c3e04a86a14546f6f0e0 Mon Sep 17 00:00:00 2001
From: Gonglei <arei.gonglei@huawei.com>
Date: Mon, 8 May 2017 13:42:53 +0800
Subject: [PATCH] qtest: emulate virtio crypto as a legacy device for
 experiment

Because the current qtest framework do not support virtio-1
or latter devices. For experimental purpose,
let's emulate the virtio crypto device as a legacy virtio
device by default. Using 0x1014 as virtio crypto pci device ID
because virtio crypto ID is 20 (0x14).

Signed-off-by: Gonglei <arei.gonglei@huawei.com>

virtio-crypto-test: add qtest case for virtio-crypto

We can simply test the functions of virtio crypto
device, including session creation, session closing,
cipher encryption and decryption.

Quick usage:
 # make tests/virtio-crypto-test && ./tests/virtio-crypto-test
  CC    tests/virtio-crypto-test.o
  LINK  tests/virtio-crypto-test
/virtio/crypto/cbc(aes-128-session-mode): OK
/virtio/crypto/cbc(aes-128-stateless-mode): OK

Signed-off-by: Gonglei <arei.gonglei@huawei.com>
[rebase on the v19 spec]
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
---
 docs/specs/pci-ids.txt        |   2 +
 hw/virtio/virtio-crypto-pci.c |   4 +-
 include/hw/pci/pci.h          |   2 +
 tests/Makefile.include        |   3 +
 tests/virtio-crypto-test.c    | 600 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 610 insertions(+), 1 deletion(-)
 create mode 100644 tests/virtio-crypto-test.c

diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt
index bb99a02..61877b7 100755
--- a/docs/specs/pci-ids.txt
+++ b/docs/specs/pci-ids.txt
@@ -22,6 +22,7 @@ maintained as part of the virtio specification.
 1af4:1004  SCSI host bus adapter device (legacy)
 1af4:1005  entropy generator device (legacy)
 1af4:1009  9p filesystem device (legacy)
+1af4:1014  crypto device (legacy)
 
 1af4:1041  network device (modern)
 1af4:1042  block device (modern)
@@ -32,6 +33,7 @@ maintained as part of the virtio specification.
 1af4:1049  9p filesystem device (modern)
 1af4:1050  virtio gpu device (modern)
 1af4:1052  virtio input device (modern)
+1af4:1054  crypto device (modern)
 
 1af4:10f0  Available for experimental usage without registration.  Must get
    to      official ID when the code leaves the test lab (i.e. when seeking
diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c
index bf64996..66a2966 100755
--- a/hw/virtio/virtio-crypto-pci.c
+++ b/hw/virtio/virtio-crypto-pci.c
@@ -37,7 +37,6 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
     }
 
     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
-    virtio_pci_force_virtio_1(vpci_dev);
     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
     object_property_set_link(OBJECT(vcrypto),
                  OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev",
@@ -53,6 +52,9 @@ static void virtio_crypto_pci_class_init(ObjectClass *klass, void *data)
     k->realize = virtio_crypto_pci_realize;
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
     dc->props = virtio_crypto_pci_properties;
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CRYPTO;
+    pcidev_k->revision = 0;
     pcidev_k->class_id = PCI_CLASS_OTHERS;
 }
 
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index e598b09..ae9327c 100755
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -83,6 +83,8 @@
 #define PCI_DEVICE_ID_VIRTIO_RNG         0x1005
 #define PCI_DEVICE_ID_VIRTIO_9P          0x1009
 #define PCI_DEVICE_ID_VIRTIO_VSOCK       0x1012
+#define PCI_DEVICE_ID_VIRTIO_CRYPTO      0x1014
+
 
 #define PCI_VENDOR_ID_REDHAT             0x1b36
 #define PCI_DEVICE_ID_REDHAT_BRIDGE      0x0001
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 37c1bed..9b6c131 100755
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -192,6 +192,8 @@ check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/char/virtio-serial-bus.c
 check-qtest-virtio-y += $(check-qtest-virtioserial-y)
 gcov-files-virtio-y += $(gcov-files-virtioserial-y)
+check-qtest-virtio-y += tests/virtio-crypto-test$(EXESUF)
+gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-crypto.c
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 gcov-files-pci-y += hw/net/e1000.c
@@ -753,6 +755,7 @@ tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
 tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o $(libqos-virtio-obj-y)
 tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o
 tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o
+tests/virtio-crypto-test$(EXESUF): tests/virtio-crypto-test.o $(libqos-virtio-obj-y)
 tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
 tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
diff --git a/tests/virtio-crypto-test.c b/tests/virtio-crypto-test.c
new file mode 100644
index 0000000..8825f1f
--- /dev/null
+++ b/tests/virtio-crypto-test.c
@@ -0,0 +1,600 @@
+/*
+ * QTest testcase for VirtIO Crypto Device
+ *
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Gonglei <arei.gonglei@huawei.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdlib.h>
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+#include "libqos/virtio-mmio.h"
+#include "libqos/pci-pc.h"
+#include "libqos/malloc.h"
+#include "libqos/malloc-pc.h"
+#include "libqos/malloc-generic.h"
+#include "qemu/bswap.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_config.h"
+#include "standard-headers/linux/virtio_ring.h"
+#include "standard-headers/linux/virtio_crypto.h"
+#include "standard-headers/linux/virtio_pci.h"
+
+#define QVIRTIO_CRYPTO_TIMEOUT_US  (30 * 1000 * 1000)
+
+#define PCI_SLOT_HP             0x06
+#define PCI_SLOT                0x04
+#define PCI_FN                  0x00
+
+/*
+ * VirtIOCryptoCipherTestData:  structure to describe a cipher test
+ * @key:    A pointer to a key used by the test
+ * @key_len:    The length of @key
+ * @iv:     A pointer to the IV/Counter used by the test
+ * @iv_len: The length of @iv
+ * @input:  A pointer to data used as input
+ * @ilen    The length of data in @input
+ * @output: A pointer to what the test need to produce
+ * @olen:   The length of data in @output
+ * @algo:   The type of algorithm, refer to VIRTIO_CRYPTO_CIPHER_AES_*
+ */
+typedef struct VirtIOCryptoCipherTestData {
+    const char *path;
+    unsigned short algo;
+    const char *key;
+    const char *iv;
+    const char *input;
+    const char *output;
+    unsigned char key_len;
+    unsigned char iv_len;
+    unsigned short ilen;
+    unsigned short olen;
+    bool is_statelss_mode;
+} VirtIOCryptoCipherTestData;
+
+
+static VirtIOCryptoCipherTestData cipher_test_data[] = {
+    { /* From RFC 3602 */
+        .path = "/virtio/crypto/cbc(aes-128-session-mode)",
+        .algo = VIRTIO_CRYPTO_CIPHER_AES_CBC,
+        .key  = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+                "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+        .key_len   = 16,
+        .iv = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+              "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+        .iv_len = 16,
+        .input  = "Single block msg",
+        .ilen   = 16,
+        .output = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
+                  "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
+        .olen   = 16,
+        .is_statelss_mode = false,
+    },
+    { /* From RFC 3602 */
+        .path = "/virtio/crypto/cbc(aes-128-stateless-mode)",
+        .algo = VIRTIO_CRYPTO_CIPHER_AES_CBC,
+        .key  = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+                "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+        .key_len   = 16,
+        .iv = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+              "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+        .iv_len = 16,
+        .input  = "Single block msg",
+        .ilen   = 16,
+        .output = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
+                  "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
+        .olen   = 16,
+        .is_statelss_mode = true,
+    },
+};
+
+static QPCIBus *virtio_crypto_test_start(void)
+{
+    char *cmdline;
+
+    cmdline = g_strdup_printf(
+               "-object cryptodev-backend-builtin,id=cryptodev0 "
+               "-device virtio-crypto-pci,id=crypto0,"
+               "cryptodev=cryptodev0");
+
+    qtest_start(cmdline);
+    g_free(cmdline);
+
+    return qpci_init_pc(NULL);
+}
+
+static void test_end(void)
+{
+    qtest_end();
+}
+
+static QVirtioPCIDevice *virtio_crypto_pci_init(QPCIBus *bus, int slot)
+{
+    QVirtioPCIDevice *dev;
+
+    dev = qvirtio_pci_device_find(bus, VIRTIO_ID_CRYPTO);
+    g_assert(dev != NULL);
+    g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_CRYPTO);
+
+    qvirtio_pci_device_enable(dev);
+    qvirtio_reset(&dev->vdev);
+    qvirtio_set_acknowledge(&dev->vdev);
+    qvirtio_set_driver(&dev->vdev);
+
+    return dev;
+}
+
+static uint64_t
+virtio_crypto_ctrl_request(QGuestAllocator *alloc,
+                           struct virtio_crypto_op_ctrl_req *req)
+{
+    uint64_t addr;
+
+    addr = guest_alloc(alloc, sizeof(*req));
+
+    memwrite(addr, req, sizeof(*req));
+
+    return addr;
+}
+
+static uint64_t
+virtio_crypto_data_request(QGuestAllocator *alloc,
+                           struct virtio_crypto_op_data_req *req)
+{
+    uint64_t addr;
+
+    addr = guest_alloc(alloc, sizeof(*req));
+
+    memwrite(addr, req, sizeof(*req));
+
+    return addr;
+}
+
+static void
+virtio_crypto_driver_init(QVirtioDevice *dev)
+{
+    /* Read configure space to get  supported crypto services */
+
+    qvirtio_set_driver_ok(dev);
+}
+
+static uint64_t
+virtio_crypto_create_session(QVirtioDevice *dev,
+            QGuestAllocator *alloc, QVirtQueue *vq,
+            VirtIOCryptoCipherTestData *data,
+            int encrypt)
+{
+    uint32_t free_head;
+    struct virtio_crypto_op_ctrl_req ctrl;
+    struct virtio_crypto_session_input input;
+    uint32_t key_len = data->key_len;
+    uint64_t req_addr;
+    uint64_t key_addr, input_addr; /* cipher key guest physical address */
+    uint64_t session_id;
+    QVRingIndirectDesc *indirect;
+
+    /* Create an encryption session */
+    ctrl.header.opcode = VIRTIO_CRYPTO_CIPHER_CREATE_SESSION;
+    ctrl.header.algo = data->algo;
+    /* Set the default dataqueue id to 0 */
+    ctrl.header.queue_id = 0;
+
+    /* Pad cipher's parameters */
+    ctrl.u.sym_create_session.op_type = VIRTIO_CRYPTO_SYM_OP_CIPHER;
+    ctrl.u.sym_create_session.u.cipher.para.algo = ctrl.header.algo;
+    ctrl.u.sym_create_session.u.cipher.para.keylen = key_len;
+    if (encrypt) {
+        ctrl.u.sym_create_session.u.cipher.para.op = VIRTIO_CRYPTO_OP_ENCRYPT;
+    } else {
+        ctrl.u.sym_create_session.u.cipher.para.op = VIRTIO_CRYPTO_OP_DECRYPT;
+    }
+
+    req_addr = virtio_crypto_ctrl_request(alloc, &ctrl);
+
+    /* Pad cipher's output data */
+    key_addr = guest_alloc(alloc, key_len);
+    memwrite(key_addr, data->key, key_len);
+
+    input.status = VIRTIO_CRYPTO_ERR;
+    input_addr = guest_alloc(alloc, sizeof(input));
+    memwrite(input_addr, &input, sizeof(input));
+
+    indirect = qvring_indirect_desc_setup(dev, alloc, 3);
+    qvring_indirect_desc_add(indirect, req_addr, sizeof(ctrl), false);
+    qvring_indirect_desc_add(indirect, key_addr, key_len, false);
+    qvring_indirect_desc_add(indirect, input_addr, sizeof(input), true);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+
+    qvirtqueue_kick(dev, vq, free_head);
+
+    qvirtio_wait_queue_isr(dev, vq, QVIRTIO_CRYPTO_TIMEOUT_US);
+
+    /* calculate the offset of input data */
+
+    memread(input_addr, &input, sizeof(input));
+
+    /* Verify the result */
+    g_assert_cmpint(input.status, ==, VIRTIO_CRYPTO_OK);
+
+    session_id = input.session_id;
+
+    g_free(indirect);
+    guest_free(alloc, input_addr);
+    guest_free(alloc, key_addr);
+    guest_free(alloc, req_addr);
+
+    return session_id;
+}
+
+static void
+virtio_crypto_close_session(QVirtioDevice *dev,
+            QGuestAllocator *alloc, QVirtQueue *vq,
+            uint64_t session_id)
+{
+    uint32_t free_head;
+    struct virtio_crypto_op_ctrl_req ctrl;
+    uint64_t req_addr, status_addr;
+    uint8_t status;
+    QVRingIndirectDesc *indirect;
+
+    /* Create an encryption session */
+    ctrl.header.opcode = VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION;
+    /* Set the default dataqueue id to 0 */
+    ctrl.header.queue_id = 0;
+
+    ctrl.u.destroy_session.session_id = session_id;
+
+    req_addr = virtio_crypto_ctrl_request(alloc, &ctrl);
+
+    status_addr = guest_alloc(alloc, sizeof(status));
+    writel(status_addr, VIRTIO_CRYPTO_ERR);
+
+    indirect = qvring_indirect_desc_setup(dev, alloc, 2);
+    qvring_indirect_desc_add(indirect, req_addr, sizeof(ctrl), false);
+    qvring_indirect_desc_add(indirect, status_addr, sizeof(status), true);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+
+    qvirtqueue_kick(dev, vq, free_head);
+
+    qvirtio_wait_queue_isr(dev, vq, QVIRTIO_CRYPTO_TIMEOUT_US);
+
+    /* Verify the result */
+    status = readl(status_addr);
+    g_assert_cmpint(status, ==, VIRTIO_CRYPTO_OK);
+
+    g_free(indirect);
+    guest_free(alloc, req_addr);
+    guest_free(alloc, status_addr);
+}
+
+
+static void
+virtio_crypto_test_cipher_session_mode(QVirtioDevice *dev,
+            QGuestAllocator *alloc, QVirtQueue *ctrlq,
+            QVirtQueue *vq, VirtIOCryptoCipherTestData *data,
+            int encrypt)
+{
+    uint32_t free_head;
+    struct virtio_crypto_op_data_req req;
+    uint64_t req_addr, status_addr;
+    uint64_t iv_addr = 0, src_addr, dst_addr;
+    uint64_t session_id;
+    char *output;
+    uint32_t src_len, dst_len;
+    uint8_t status;
+    QVRingIndirectDesc *indirect;
+    uint8_t entry_num;
+
+    /* Create a session */
+    session_id = virtio_crypto_create_session(dev, alloc,
+                                             ctrlq, data, encrypt);
+
+    /* Head of operation */
+    req.header.session_id = session_id;
+    if (encrypt) {
+        req.header.opcode = VIRTIO_CRYPTO_CIPHER_ENCRYPT;
+    } else {
+        req.header.opcode = VIRTIO_CRYPTO_CIPHER_DECRYPT;
+    }
+
+    req.u.sym_req.op_type = VIRTIO_CRYPTO_SYM_OP_CIPHER;
+    req.u.sym_req.u.cipher.para.iv_len = data->iv_len;
+    req.u.sym_req.u.cipher.para.src_data_len = data->ilen;
+    req.u.sym_req.u.cipher.para.dst_data_len = data->olen;
+
+    req_addr = virtio_crypto_data_request(alloc, &req);
+
+    /* IV */
+    if (data->iv_len > 0) {
+        iv_addr = guest_alloc(alloc, data->iv_len);
+        memwrite(iv_addr, data->iv, data->iv_len);
+
+        /* header + iv + src + dst + status */
+        entry_num = 5;
+    } else {
+        /* header + src + dst + status */
+        entry_num = 4;
+    }
+
+    if (encrypt) {
+        src_len = data->ilen;
+        dst_len = data->olen;
+        /* Source data is the input data which is a single buffer */
+        src_addr = guest_alloc(alloc, src_len);
+        memwrite(src_addr, data->input, src_len);
+    } else {
+        src_len = data->olen;
+        dst_len = data->ilen;
+        /* Source data is the output data which is a single buffer */
+        src_addr = guest_alloc(alloc, src_len);
+        memwrite(src_addr, data->output, src_len);
+    }
+
+    dst_addr = guest_alloc(alloc, dst_len);
+
+    status_addr = guest_alloc(alloc, sizeof(status));
+    writel(status_addr, VIRTIO_CRYPTO_ERR);
+
+    /* Allocate descripto table entries */
+    indirect = qvring_indirect_desc_setup(dev, alloc, entry_num);
+    qvring_indirect_desc_add(indirect, req_addr, sizeof(req), false);
+    if (data->iv_len > 0) {
+        qvring_indirect_desc_add(indirect, iv_addr, data->iv_len, false);
+    }
+    qvring_indirect_desc_add(indirect, src_addr, src_len, false);
+    qvring_indirect_desc_add(indirect, dst_addr, dst_len, true);
+    qvring_indirect_desc_add(indirect, status_addr, sizeof(status), true);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+
+    qvirtqueue_kick(dev, vq, free_head);
+
+    qvirtio_wait_queue_isr(dev, vq, QVIRTIO_CRYPTO_TIMEOUT_US);
+
+    /* Verify the result */
+    status = readl(status_addr);
+    g_assert_cmpint(status, ==, VIRTIO_CRYPTO_OK);
+
+    output = g_malloc0(dst_len);
+    memread(dst_addr, output, dst_len);
+    if (encrypt) {
+        g_assert_cmpstr(output, ==, data->output);
+    } else {
+        g_assert_cmpstr(output, ==, data->input);
+    }
+    g_free(output);
+
+    g_free(indirect);
+
+    if (data->iv_len > 0) {
+        guest_free(alloc, iv_addr);
+    }
+    guest_free(alloc, src_addr);
+    guest_free(alloc, dst_addr);
+    guest_free(alloc, req_addr);
+    guest_free(alloc, status_addr);
+
+    /* Close the session */
+    virtio_crypto_close_session(dev, alloc, ctrlq, session_id);
+}
+
+static void
+virtio_crypto_test_cipher_stateless_mode(QVirtioDevice *dev,
+            QGuestAllocator *alloc,
+            QVirtQueue *vq, VirtIOCryptoCipherTestData *data,
+            int encrypt)
+{
+    uint32_t free_head;
+    struct virtio_crypto_op_data_req_mux req;
+    struct virtio_crypto_sym_data_req_stateless para;
+    uint64_t req_addr, para_addr, status_addr;
+    uint64_t iv_addr = 0, src_addr, dst_addr, key_addr;
+    char *output;
+    uint32_t src_len, dst_len;
+    uint8_t status;
+    QVRingIndirectDesc *indirect;
+    uint8_t entry_num;
+
+    /* Head of operation */
+    req.header.flag = 0;
+    if (encrypt) {
+        req.header.opcode = VIRTIO_CRYPTO_CIPHER_ENCRYPT;
+        para.u.cipher.para.sess_para.op = VIRTIO_CRYPTO_OP_ENCRYPT;
+    } else {
+        req.header.opcode = VIRTIO_CRYPTO_CIPHER_DECRYPT;
+        para.u.cipher.para.sess_para.op = VIRTIO_CRYPTO_OP_DECRYPT;
+    }
+
+    para.op_type = VIRTIO_CRYPTO_SYM_OP_CIPHER;
+    para.u.cipher.para.sess_para.algo = data->algo;
+    para.u.cipher.para.sess_para.keylen = data->key_len;
+    para.u.cipher.para.iv_len = data->iv_len;
+    para.u.cipher.para.src_data_len = data->ilen;
+    para.u.cipher.para.dst_data_len = data->olen;
+
+    req_addr = guest_alloc(alloc, sizeof(req));
+    memwrite(req_addr, &req, sizeof(req));
+
+    para_addr = guest_alloc(alloc, sizeof(para));
+    memwrite(para_addr, &para, sizeof(para));
+
+    g_assert(data->key_len > 0);
+    key_addr = guest_alloc(alloc, data->key_len);
+    memwrite(key_addr, data->key, data->key_len);
+
+    /* IV */
+    if (data->iv_len > 0) {
+        iv_addr = guest_alloc(alloc, data->iv_len);
+        memwrite(iv_addr, data->iv, data->iv_len);
+
+        /* header + key + iv + src + dst + status */
+        entry_num = 7;
+    } else {
+        /* header + key + src + dst + status */
+        entry_num = 6;
+    }
+
+    if (encrypt) {
+        src_len = data->ilen;
+        dst_len = data->olen;
+        /* Source data is the input data which is a single buffer */
+        src_addr = guest_alloc(alloc, src_len);
+        memwrite(src_addr, data->input, src_len);
+    } else {
+        src_len = data->olen;
+        dst_len = data->ilen;
+        /* Source data is the output data which is a single buffer */
+        src_addr = guest_alloc(alloc, src_len);
+        memwrite(src_addr, data->output, src_len);
+    }
+
+    dst_addr = guest_alloc(alloc, dst_len);
+
+    status_addr = guest_alloc(alloc, sizeof(status));
+    writel(status_addr, VIRTIO_CRYPTO_ERR);
+
+    /* Allocate desc table entries */
+    indirect = qvring_indirect_desc_setup(dev, alloc, entry_num);
+    qvring_indirect_desc_add(indirect, req_addr, sizeof(req), false);
+    qvring_indirect_desc_add(indirect, para_addr, sizeof(para), false);
+    qvring_indirect_desc_add(indirect, key_addr, data->key_len, false);
+    if (data->iv_len > 0) {
+        qvring_indirect_desc_add(indirect, iv_addr, data->iv_len, false);
+    }
+    qvring_indirect_desc_add(indirect, src_addr, src_len, false);
+    qvring_indirect_desc_add(indirect, dst_addr, dst_len, true);
+    qvring_indirect_desc_add(indirect, status_addr, sizeof(status), true);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+
+    qvirtqueue_kick(dev, vq, free_head);
+
+    qvirtio_wait_queue_isr(dev, vq, QVIRTIO_CRYPTO_TIMEOUT_US);
+
+    /* Verify the result */
+    status = readl(status_addr);
+    g_assert_cmpint(status, ==, VIRTIO_CRYPTO_OK);
+
+    output = g_malloc0(dst_len);
+    memread(dst_addr, output, dst_len);
+    if (encrypt) {
+        g_assert_cmpstr(output, ==, data->output);
+    } else {
+        g_assert_cmpstr(output, ==, data->input);
+    }
+    g_free(output);
+
+    g_free(indirect);
+    guest_free(alloc, key_addr);
+    if (data->iv_len > 0) {
+        guest_free(alloc, iv_addr);
+    }
+    guest_free(alloc, src_addr);
+    guest_free(alloc, dst_addr);
+    guest_free(alloc, para_addr);
+    guest_free(alloc, req_addr);
+    guest_free(alloc, status_addr);
+}
+
+static void
+virtio_crypto_test_cipher(QVirtioDevice *dev,
+            QGuestAllocator *alloc, QVirtQueue *ctrlq,
+            QVirtQueue *dataq, VirtIOCryptoCipherTestData *data,
+            int encrypt)
+{
+    if (!data->is_statelss_mode) {
+        virtio_crypto_test_cipher_session_mode(dev, alloc,
+            ctrlq, dataq, data, encrypt);
+    } else {
+        virtio_crypto_test_cipher_stateless_mode(dev, alloc,
+            dataq, data, encrypt);
+    }
+}
+
+static void virtio_crypto_pci_basic(void *opaque)
+{
+    VirtIOCryptoCipherTestData *test_data = opaque;
+    QVirtioPCIDevice *dev;
+    QPCIBus *bus;
+    QGuestAllocator *alloc;
+    QVirtQueuePCI *dataq, *controlq;
+    uint32_t features;
+
+    bus = virtio_crypto_test_start();
+    dev = virtio_crypto_pci_init(bus, PCI_SLOT);
+
+    alloc = pc_alloc_init();
+
+    features = qvirtio_get_features(&dev->vdev);
+    g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
+
+    if (!test_data->is_statelss_mode) {
+        features = features & ~(QVIRTIO_F_BAD_FEATURE |
+                                (1u << VIRTIO_RING_F_EVENT_IDX |
+                                1u << VIRTIO_CRYPTO_F_MUX_MODE |
+                                1u << VIRTIO_CRYPTO_F_CIPHER_STATELESS_MODE));
+    } else {
+        features = features & ~(QVIRTIO_F_BAD_FEATURE |
+                                (1u << VIRTIO_RING_F_EVENT_IDX));
+    }
+    qvirtio_set_features(&dev->vdev, features);
+
+    dataq = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev,
+                                           alloc, 0);
+    controlq = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev,
+                                           alloc, 1);
+
+    virtio_crypto_driver_init(&dev->vdev);
+
+    /* Step 1: Encryption */
+    virtio_crypto_test_cipher(&dev->vdev, alloc,
+                              &controlq->vq, &dataq->vq,
+                              test_data, 1);
+    /* Step 2: Decryption */
+    virtio_crypto_test_cipher(&dev->vdev, alloc,
+                              &controlq->vq, &dataq->vq,
+                              test_data, 0);
+
+    /* End test */
+    guest_free(alloc, dataq->vq.desc);
+    guest_free(alloc, controlq->vq.desc);
+    pc_alloc_uninit(alloc);
+    qvirtio_pci_device_disable(dev);
+    g_free(dev);
+    qpci_free_pc(bus);
+    test_end();
+}
+
+int main(int argc, char **argv)
+{
+    const char *qemu;
+    const char *arch;
+    int i, ret;
+
+    qemu = getenv("QTEST_QEMU_BINARY");
+    if (qemu == NULL) {
+        ret = setenv("QTEST_QEMU_BINARY",
+                     "x86_64-softmmu/qemu-system-x86_64", 0);
+        g_assert(ret == 0);
+    }
+
+    arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        for (i = 0; i < G_N_ELEMENTS(cipher_test_data); i++) {
+            g_test_add_data_func(cipher_test_data[i].path,
+                                 (void *)&cipher_test_data[i],
+                                 (GTestDataFunc)virtio_crypto_pci_basic);
+        }
+    }
+
+    return g_test_run();
+}
-- 
1.8.3.1


[-- Attachment #3: Type: text/plain, Size: 208 bytes --]


---------------------------------------------------------------------
To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org

  reply	other threads:[~2017-09-14  0:59 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-11  1:10 [Qemu-devel] [RFC 0/8] virtio-crypto: add multiplexing mode support Longpeng(Mike)
2017-09-11  1:10 ` [virtio-dev] " Longpeng(Mike)
2017-09-11  1:10 ` [Qemu-devel] [RFC 1/8] virtio-crypto: add new definations for multiplexing mode Longpeng(Mike)
2017-09-11  1:10   ` [virtio-dev] " Longpeng(Mike)
2017-09-11  1:10 ` [Qemu-devel] [RFC 2/8] virtio-crypto: add session creation logic for mux mode Longpeng(Mike)
2017-09-11  1:10   ` [virtio-dev] " Longpeng(Mike)
2017-09-11  1:10 ` [Qemu-devel] [RFC 3/8] virtio-crypto: add dataq operation " Longpeng(Mike)
2017-09-11  1:10   ` [virtio-dev] " Longpeng(Mike)
2017-09-11  1:10 ` [Qemu-devel] [RFC 4/8] cryptodev: add stateless mode cipher support Longpeng(Mike)
2017-09-11  1:10   ` [virtio-dev] " Longpeng(Mike)
2017-09-11  1:10 ` [Qemu-devel] [RFC 5/8] virtio-crypto: add stateless crypto request handler Longpeng(Mike)
2017-09-11  1:10   ` [virtio-dev] " Longpeng(Mike)
2017-09-11  1:10 ` [Qemu-devel] [RFC 6/8] cryptodev: extract one util function Longpeng(Mike)
2017-09-11  1:10   ` [virtio-dev] " Longpeng(Mike)
2017-09-11  1:10 ` [Qemu-devel] [RFC 7/8] cryptodev-builtin: add stateless cipher support Longpeng(Mike)
2017-09-11  1:10   ` [virtio-dev] " Longpeng(Mike)
2017-09-11  1:10 ` [Qemu-devel] [RFC 8/8] virtio-crypto: add host feature bits support Longpeng(Mike)
2017-09-11  1:10   ` [virtio-dev] " Longpeng(Mike)
2017-09-11  1:26 ` [Qemu-devel] [RFC 0/8] virtio-crypto: add multiplexing mode support no-reply
2017-09-11  1:26   ` no-reply
2017-09-13 18:14 ` Halil Pasic
2017-09-13 18:14   ` [virtio-dev] " Halil Pasic
2017-09-14  0:58   ` Longpeng (Mike) [this message]
2017-09-14  0:58     ` Longpeng (Mike)
2017-09-15 17:33     ` [Qemu-devel] [virtio-dev] " Halil Pasic
2017-09-15 17:33       ` [virtio-dev] " Halil Pasic
2017-09-18  1:17       ` [Qemu-devel] [virtio-dev] " Longpeng (Mike)
2017-09-18  1:17         ` [virtio-dev] Re: [Qemu-devel] " Longpeng (Mike)
2017-10-06 14:24         ` [Qemu-devel] [virtio-dev] " Halil Pasic
2017-10-06 14:24           ` [virtio-dev] " Halil Pasic
2017-10-09  9:22           ` Gonglei (Arei)
2017-10-09  9:22             ` [virtio-dev] " Gonglei (Arei)
2017-10-09 11:04             ` Halil Pasic
2017-10-09 11:04               ` [virtio-dev] " Halil Pasic
2017-10-09 11:17               ` Gonglei (Arei)
2017-10-09 11:17                 ` [virtio-dev] " Gonglei (Arei)
2017-10-10  8:35                 ` Longpeng (Mike)
2017-10-10  8:35                   ` [virtio-dev] " Longpeng (Mike)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=59B9D439.10807@huawei.com \
    --to=longpeng2@huawei.com \
    --cc=Jani.Kokkonen@huawei.com \
    --cc=Ola.Liljedahl@arm.com \
    --cc=Varun.Sethi@freescale.com \
    --cc=agraf@suse.de \
    --cc=arei.gonglei@hotmail.com \
    --cc=arei.gonglei@huawei.com \
    --cc=brian.a.keating@intel.com \
    --cc=cohuck@redhat.com \
    --cc=denglingli@chinamobile.com \
    --cc=jasowang@redhat.com \
    --cc=john.griffin@intel.com \
    --cc=liang.j.ma@intel.com \
    --cc=luonengjun@huawei.com \
    --cc=mike.caraman@nxp.com \
    --cc=mst@redhat.com \
    --cc=pasic@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    --cc=vincent.jardin@6wind.com \
    --cc=virtio-dev@lists.oasis-open.org \
    --cc=wangxinxin.wang@huawei.com \
    --cc=weidong.huang@huawei.com \
    --cc=xin.zeng@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.