Skip to content

Commit 2035456

Browse files
author
Dorinda Bassey
committed
Add VhostUserRng device implementation
Implements a vhost-user RNG device as a thin wrapper around the core VhostUserDevice. The VMM now switches between the standard RNG device and vhost-user RNG depending on whether a socket path is configured via krun_set_vhost_user_rng() This allows us to use the RNG device from the rust-vmm vhost-device running in a separate process for better isolation and flexibility. Signed-off-by: Dorinda Bassey <dbassey@redhat.com>
1 parent b2bd509 commit 2035456

5 files changed

Lines changed: 138 additions & 2 deletions

File tree

src/devices/src/virtio/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub use self::rng::*;
5959
#[cfg(feature = "snd")]
6060
pub use self::snd::Snd;
6161
#[cfg(feature = "vhost-user")]
62-
pub use self::vhost_user::VhostUserDevice;
62+
pub use self::vhost_user::{VhostUserDevice, VhostUserRng};
6363
pub use self::vsock::*;
6464

6565
/// When the driver initializes the device, it lets the device know about the

src/devices/src/virtio/vhost_user/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@
77
//! to run in separate processes for better isolation and flexibility.
88
99
mod device;
10+
mod rng;
1011

1112
pub use device::VhostUserDevice;
13+
pub use rng::VhostUserRng;
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright 2026, Red Hat Inc. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! Vhost-user RNG device implementation.
5+
6+
use std::io::Result as IoResult;
7+
8+
use vm_memory::GuestMemoryMmap;
9+
10+
use super::device::VhostUserDevice;
11+
use crate::virtio::{ActivateResult, InterruptTransport, Queue as VirtQueue, VirtioDevice};
12+
13+
// RNG device constants
14+
const RNG_DEV_ID: &str = "vhost_user_rng";
15+
const NUM_QUEUES: usize = 1;
16+
const QUEUE_SIZES: &[u16] = &[256; NUM_QUEUES];
17+
const VIRTIO_ID_RNG: u32 = 4;
18+
19+
/// Vhost-user RNG device.
20+
///
21+
/// This is a thin wrapper around VhostUserDevice specialized for the RNG device type.
22+
pub struct VhostUserRng {
23+
inner: VhostUserDevice,
24+
}
25+
26+
impl VhostUserRng {
27+
/// Create a new vhost-user RNG device.
28+
pub fn new(socket_path: &str) -> IoResult<Self> {
29+
let queues: Vec<VirtQueue> = QUEUE_SIZES
30+
.iter()
31+
.map(|&max_size| VirtQueue::new(max_size))
32+
.collect();
33+
34+
let inner =
35+
VhostUserDevice::new(socket_path, VIRTIO_ID_RNG, RNG_DEV_ID.to_string(), queues)?;
36+
37+
Ok(VhostUserRng { inner })
38+
}
39+
40+
pub fn id(&self) -> &str {
41+
RNG_DEV_ID
42+
}
43+
}
44+
45+
impl VirtioDevice for VhostUserRng {
46+
fn device_type(&self) -> u32 {
47+
self.inner.device_type()
48+
}
49+
50+
fn device_name(&self) -> &str {
51+
self.inner.device_name()
52+
}
53+
54+
fn queues(&self) -> &[VirtQueue] {
55+
self.inner.queues()
56+
}
57+
58+
fn queues_mut(&mut self) -> &mut [VirtQueue] {
59+
self.inner.queues_mut()
60+
}
61+
62+
fn queue_events(&self) -> &[utils::eventfd::EventFd] {
63+
self.inner.queue_events()
64+
}
65+
66+
fn avail_features(&self) -> u64 {
67+
self.inner.avail_features()
68+
}
69+
70+
fn acked_features(&self) -> u64 {
71+
self.inner.acked_features()
72+
}
73+
74+
fn set_acked_features(&mut self, acked_features: u64) {
75+
self.inner.set_acked_features(acked_features)
76+
}
77+
78+
fn read_config(&self, offset: u64, data: &mut [u8]) {
79+
self.inner.read_config(offset, data)
80+
}
81+
82+
fn write_config(&mut self, offset: u64, data: &[u8]) {
83+
self.inner.write_config(offset, data)
84+
}
85+
86+
fn activate(&mut self, mem: GuestMemoryMmap, interrupt: InterruptTransport) -> ActivateResult {
87+
self.inner.activate(mem, interrupt)
88+
}
89+
90+
fn is_activated(&self) -> bool {
91+
self.inner.is_activated()
92+
}
93+
94+
fn reset(&mut self) -> bool {
95+
self.inner.reset()
96+
}
97+
}

src/vmm/src/builder.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,17 @@ pub fn build_microvm(
974974
#[cfg(not(feature = "tee"))]
975975
attach_balloon_device(&mut vmm, event_manager, intc.clone())?;
976976
#[cfg(not(feature = "tee"))]
977-
attach_rng_device(&mut vmm, event_manager, intc.clone())?;
977+
{
978+
#[cfg(feature = "vhost-user")]
979+
if let Some(ref socket_path) = vm_resources.vhost_user_rng_socket {
980+
attach_vhost_user_rng_device(&mut vmm, intc.clone(), socket_path)?;
981+
} else {
982+
attach_rng_device(&mut vmm, event_manager, intc.clone())?;
983+
}
984+
985+
#[cfg(not(feature = "vhost-user"))]
986+
attach_rng_device(&mut vmm, event_manager, intc.clone())?;
987+
}
978988
let mut console_id = 0;
979989
if !vm_resources.disable_implicit_console {
980990
attach_console_devices(
@@ -2387,6 +2397,28 @@ fn attach_rng_device(
23872397
Ok(())
23882398
}
23892399

2400+
#[cfg(not(feature = "tee"))]
2401+
#[cfg(feature = "vhost-user")]
2402+
fn attach_vhost_user_rng_device(
2403+
vmm: &mut Vmm,
2404+
intc: IrqChip,
2405+
socket_path: &str,
2406+
) -> std::result::Result<(), StartMicrovmError> {
2407+
use self::StartMicrovmError::*;
2408+
2409+
let rng = Arc::new(Mutex::new(
2410+
devices::virtio::VhostUserRng::new(socket_path)
2411+
.map_err(|e| RegisterRngDevice(device_manager::mmio::Error::VhostUserDevice(e)))?,
2412+
));
2413+
2414+
let id = String::from(rng.lock().unwrap().id());
2415+
2416+
// The device mutex mustn't be locked here otherwise it will deadlock.
2417+
attach_mmio_device(vmm, id, intc.clone(), rng).map_err(RegisterRngDevice)?;
2418+
2419+
Ok(())
2420+
}
2421+
23902422
#[cfg(feature = "gpu")]
23912423
#[allow(clippy::too_many_arguments)]
23922424
fn attach_gpu_device(

src/vmm/src/device_manager/kvm/mmio.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ pub enum Error {
4141
DeviceNotFound,
4242
/// Failed to update the mmio device.
4343
UpdateFailed,
44+
/// Failed to create vhost-user device.
45+
#[cfg(feature = "vhost-user")]
46+
VhostUserDevice(io::Error),
4447
}
4548

4649
impl fmt::Display for Error {
@@ -59,6 +62,8 @@ impl fmt::Display for Error {
5962
Error::RegisterIrqFd(ref e) => write!(f, "failed to register irqfd: {e}"),
6063
Error::DeviceNotFound => write!(f, "the device couldn't be found"),
6164
Error::UpdateFailed => write!(f, "failed to update the mmio device"),
65+
#[cfg(feature = "vhost-user")]
66+
Error::VhostUserDevice(ref e) => write!(f, "failed to create vhost-user device: {e}"),
6267
}
6368
}
6469
}

0 commit comments

Comments
 (0)