Features/VirtIORNG

From QEMU

Summary

VirtIO RNG is a paravirtualized device that is exposed as a hardware RNG device to the guest. On the host side, it can be wired up to one of several sources of entropy, including a real hardware RNG device as well as the host's /dev/random if hardware support doesn't exist.

Status

Support for the VirtIO RNG device has been added to the QEMU sources starting from commit a9b7b2ad7b075dba5495271706670e5c6b1304bc. This is part of the QEMU 1.3 release. The Linux kernel contains the guest driver for the device since version 2.6.26.

Invocation

Just adding

-device virtio-rng-pci

to the QEMU invocation will add the device with a default host backend. As of QEMU 1.3, the default backend is to use the host's /dev/random as a source of entropy.

To modify this source to a real hardware RNG on the host, use:

-object rng-random,filename=/dev/hwrng,id=rng0 \
-device virtio-rng-pci,rng=rng0

This passes on any data received from the hardware RNG (via /dev/hwrng) directly to the guest.

Optional parameters to limit the rate of data sent to the guest are inlucded:

-device virtio-rng-pci,max-bytes=1024,period=1000

This restricts the data sent to the guest at 1KB per second. This is useful to not let a guest starve the host of entropy.

Effect of the period parameter

(by Amos Kong <akong AT redhat.com>)
When we set a fixed rate speed, we can use different periods. The
period still effect the stable of system IO.
If the period is too large, and we set a higher speed, then IO will wave.

Example:  the IO max speed is 20 M/s, and we test 5 mins
          it clear that the first period is better

_Theory_ Condition:

* period 1:   20M / 1s
  from 0 ~ 20 second, read packets,
  from 21 ~ 100 second, wait ...

  from 0 ~ 20 second, read packets,
  from 21 ~ 100 second, wait ...

  from 260 ~ 281 second, read packets,
  from 281 ~ 300 second, wait ...

* period 2:   100M / 5
  from 0 ~ 60 second, read packets,
  from 61 ~ 300 second, wait ...

Smaller period is better, but smaller period will cause more timer
expired, and IO wave will be balance by scheduling other process.

Communicating with the EGD Protocol

 # ./readbytes (listen 1024 port, read data from some source, and send to remote client socket)

 # qemu-kvm ...... \
 -chardev socket,host=10.66.4.212,port=1024,id=chr0 \
 -object rng-egd,chardev=chr0,id=rng0 \
 -device virtio-rng-pci,rng=rng0

usage of real rng device(QNG PQ4000KU)

Config the real rng device(QNG PQ4000KU), read data from the device by libqwqng API. Transfer data to qemu (w/ virt-rng EGD backend) by a socket.

More detail: Features/Real rng device

Testing

On the host

Test if the host device is opened when qemu is started. In the default case, when /dev/random is used, check the output of

lsof /dev/random

Before starting QEMU, the output of the previous command shouldn't show qemu. After starting the guest, the output of the command should show the qemu instance, like:

$ lsof /dev/random
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
qemu-syst 9075 amit   12r   CHR    1,8      0t0 1032 /dev/random

On the guest

Check if the hardware RNG core has detected virtio-rng as a source of entropy:

$ cat /sys/devices/virtual/misc/hw_random/rng_available
virtio

Check what is the current hwrng device in use by the kernel:

$ cat /sys/devices/virtual/misc/hw_random/rng_current
virtio

If the current source is virtio, just reading from the hwrng device will fetch the data from the host:

# cat /dev/hwrng

Without virtio-rng, the /dev/hwrng file won't be available. With virtio-rng, the file will be available, and will show some output. Output may be slow to arrive, as this depends on the amount of entropy the host has to give. Doing mouse, keyboard, network, block activity on the host will accelerate the speed with which the host can give out data to the default /dev/random source.

Next, hook up the virtio-rng hwrng to the guest's entropy pool by running rngd:

# rngd -r /dev/hwrng

Compare the results of

$ cat /dev/random

inside a guest with and without the virtio rng device. The data should flow faster when the virtio rng device is present.

TODO

Intel CPUs will introduce an RDRAND instruction that can give random bytes. This instruction can be directly made available to guests, so the guests won't have to rely on virtio-rng. However, announcing the availability of the RDRAND instruction on the host may not be desirable due to live migration constraints. Using RDRAND on the host, if available, as a source of entropy to pass on to the guest via virtio-rng is better than the current /dev/random source. The RDSEED instruction, in a future Intel processor, will output real entropy (instead of just random numbers that the RDRAND outputs). Using RDSEED as a source is equivalent to using a real hardware rng. This has the advantage of not depleting the host's entropy pool, as well as passing real entropy to the guest instead of CSPRNG.

The performance rng-egd backend is very bad, the request queue doesn't work actually. Another request will come when the first request is processed by chr_read(). I have a solution to improve the performance, we can use a cache queue to pre-read randome data, when request is coming, it give quick feedback if the data is prepared. We can use the space time to fill the cache queue. In my testing, the read speed can be improved from 0.9k/s to 500k/s

More Information

There is some more information on this feature, and testing instructions at these links: