Features/Real rng device

From QEMU

Author

Amos Kong <akong@redhat.com>

Background

Virtio-rng currently have two kinds of backends, random-backend and egd-backend. The first backend will open a file (eg /dev/random) and read data from the file descriptor, it's recommended backend. The second backend is reading data from a char device, it can be a socket client or server which connects with egd server.

When we use egd backend, the speed is slower than first backend. But encrypt data is very expensive, we can't solve the speed issue by caching, and current speed is enough for guest system.

Device Description

"QNG PQ4000KU" is USB hardware device, which is used to generate real random data by hardware. The driver name in linux is fsbi_*

We access the device by libqwqng API, QEMU can read random data from a remote socket(server). So we write a CPP program to read data from device and send the data to remote socket(client).

Install libqwqng (reference QWQNG_Linux.pdf in the provided setup-CD)

  • Compile and install the following lib (packages are provided in the setup-CD):
    • libusb-1.0
    • libFTDI1
    • LIBQWQNG-1.3.5
  • Update udev rules to change QNG device's permission
    • create plugdev group if it doesn't exist
    • more detail please reference Section 6 in QWQNG_Linux.pdf
# cp ~/libqwqng-1.3.5/packages/45-libqwqng.rules /etc/udev/rules.d/
# udevadm control --reload-rules
# groupadd plugdev
# usermod -G plugdev -a USER
  • Compile and execute test examples to verify libQWQNG works
host) # cd libqwqng-1.3.5/examples/
host) # make
host) # ./randbytes

Expected result: can read 10 bytes data, which will be converted to hex format.

About socket interface

UDP socket chardev is just a data channel. If qemu set a connect UDP socket(client), you should create a listen UDP socket(server), and write the random data to remote socket when client connects the server.

If qemu set a listen UDP socket, you should create a connect UDP socket, and try to connect the server socket, and write data to remote socket.

It's same with TCP socket, or unix socket.

Read data from dev by QWQNG API

Write a CPP program, add it to "libqwqng-1.3.5/examples/" for compiling

  char* randbyte;
  int bytecount = 10;
  QNG = new QWQNG();
  QNG->RandBytes(randbyte, bytecount))

  delete [] randbyte;
  delete QNG;

Write data to the remote socket

  int sock_fd, accept_sock;
  struct sockaddr_in server_addr;

  server_addr.sin_family=AF_INET;
  server_addr.sin_port=htons(1024);
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

  sock_fd = socket(PF_INET, SOCK_STREAM, 0);
  bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr);
  listen(sock_fd,4);
  accept_sock = accept(sock_fd, NULL, NULL);
  while (1)
    send(accept_sock, randbyte, sizeof(randbyte), 0);

The whole CPP program: Features/Real_rng_device/VirtRng-RandBytes.cpp

host) # cp libqwqng-1.3.5/examples/RandBytes.cpp libqwqng-1.3.5/examples/RandBytes.cpp.bak
host) # cp RandBytes.cpp libqwqng-1.3.5/examples/
host) # cd libqwqng-1.3.5/examples/
host) # make
host) # ./randbytes

Launch qemu with the virtio-rng backend of socket rng-egd

# qemu-kvm -vnc :0 -snapshot /images/RHEL-Server-6.4-64-virtio.qcow2 \
 -monitor stdio --enable-kvm -m 2000 \
 -chardev socket,host=10.66.4.212,port=1024,id=chr0 \
 -object rng-egd,chardev=chr0,id=rng0 \
 -device virtio-rng-pci,rng=rng0

note: 10.66.4.212 is the IP address of the host that is executing "./randbytes"

Guest can read random data from /dev/hwrng

  guest) # dd if=/dev/hwrng of=/dev/stdout

Expected result: randome data is outputted to the terminal.