virtio-devices: Embed VirtioCommon in VhostUserCommon

Since vhost-user devices are always virtio devices it makes sense to
structure this struct inside the VhostUserCommon struct. This then also
makes some of the methods on VhostUserCommon cleaner since they can now
act directly on the common virtio bits (e.g. for kill_evt)

Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
Rob Bradford
2026-03-31 04:31:35 -07:00
parent db93c6fdc7
commit a0bbef3a76
5 changed files with 145 additions and 139 deletions

View File

@@ -41,7 +41,6 @@ struct BackendReqHandler {}
impl VhostUserFrontendReqHandler for BackendReqHandler {}
pub struct Net {
common: VirtioCommon,
vu_common: VhostUserCommon,
id: String,
config: VirtioNetConfig,
@@ -198,17 +197,17 @@ impl Net {
Ok(Net {
id,
common: VirtioCommon {
device_type: VirtioDeviceType::Net as u32,
queue_sizes: vec![vu_cfg.queue_size; num_queues],
avail_features,
acked_features,
paused_sync: Some(Arc::new(Barrier::new(2))),
min_queues: DEFAULT_QUEUE_NUMBER as u16,
paused: Arc::new(AtomicBool::new(paused)),
..Default::default()
},
vu_common: VhostUserCommon {
virtio_common: VirtioCommon {
device_type: VirtioDeviceType::Net as u32,
queue_sizes: vec![vu_cfg.queue_size; num_queues],
avail_features,
acked_features,
paused_sync: Some(Arc::new(Barrier::new(2))),
min_queues: DEFAULT_QUEUE_NUMBER as u16,
paused: Arc::new(AtomicBool::new(paused)),
..Default::default()
},
vu: Some(Arc::new(Mutex::new(vu))),
acked_protocol_features,
socket_path: vu_cfg.socket,
@@ -228,19 +227,19 @@ impl Net {
}
fn state(&self) -> std::result::Result<State, MigratableError> {
self.vu_common.state(&self.common, self.config)
self.vu_common.state(self.config)
}
}
impl Drop for Net {
fn drop(&mut self) {
if let Some(kill_evt) = self.common.kill_evt.take()
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take()
&& let Err(e) = kill_evt.write(1)
{
error!("failed to kill vhost-user-net: {e:?}");
}
self.common.wait_for_epoll_threads();
self.vu_common.virtio_common.wait_for_epoll_threads();
if let Some(thread) = self.epoll_thread.take()
&& let Err(e) = thread.join()
@@ -258,15 +257,15 @@ impl Drop for Net {
impl VirtioDevice for Net {
fn device_type(&self) -> u32 {
self.common.device_type
self.vu_common.virtio_common.device_type
}
fn queue_max_sizes(&self) -> &[u16] {
&self.common.queue_sizes
&self.vu_common.virtio_common.queue_sizes
}
fn features(&self) -> u64 {
let mut features = self.common.avail_features;
let mut features = self.vu_common.virtio_common.avail_features;
if self.iommu {
features |= 1u64 << VIRTIO_F_ACCESS_PLATFORM;
}
@@ -274,7 +273,7 @@ impl VirtioDevice for Net {
}
fn ack_features(&mut self, value: u64) {
self.common.ack_features(value);
self.vu_common.virtio_common.ack_features(value);
}
fn read_config(&self, offset: u64, data: &mut [u8]) {
@@ -288,18 +287,28 @@ impl VirtioDevice for Net {
mut queues,
..
} = context;
self.common.activate(&queues, interrupt_cb.clone())?;
self.vu_common
.virtio_common
.activate(&queues, interrupt_cb.clone())?;
self.guest_memory = Some(mem.clone());
let num_queues = queues.len();
let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && !num_queues.is_multiple_of(2) {
let event_idx = self
.vu_common
.virtio_common
.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
if self
.vu_common
.virtio_common
.feature_acked(VIRTIO_NET_F_CTRL_VQ.into())
&& !num_queues.is_multiple_of(2)
{
let ctrl_queue_index = num_queues - 1;
let (_, mut ctrl_queue, ctrl_queue_evt) = queues.remove(ctrl_queue_index);
ctrl_queue.set_event_idx(event_idx);
let (kill_evt, pause_evt) = self.common.dup_eventfds();
let (kill_evt, pause_evt) = self.vu_common.virtio_common.dup_eventfds();
let mut ctrl_handler = NetCtrlEpollHandler {
mem: mem.clone(),
@@ -313,12 +322,12 @@ impl VirtioDevice for Net {
queue_index: ctrl_queue_index as u16,
};
let paused = self.common.paused.clone();
let paused = self.vu_common.virtio_common.paused.clone();
// Let's update the barrier as we need 1 for the control queue
// thread + 1 for the common vhost-user thread + 1 for the main
// thread signalling the pause.
self.common.paused_sync = Some(Arc::new(Barrier::new(3)));
let paused_sync = self.common.paused_sync.clone();
self.vu_common.virtio_common.paused_sync = Some(Arc::new(Barrier::new(3)));
let paused_sync = self.vu_common.virtio_common.paused_sync.clone();
let mut epoll_threads = Vec::new();
spawn_virtio_thread(
@@ -336,11 +345,12 @@ impl VirtioDevice for Net {
// The backend acknowledged features must not contain VIRTIO_NET_F_MAC
// since we don't expect the backend to handle it.
let backend_acked_features = self.common.acked_features & !(1 << VIRTIO_NET_F_MAC);
let backend_acked_features =
self.vu_common.virtio_common.acked_features & !(1 << VIRTIO_NET_F_MAC);
// Run a dedicated thread for handling potential reconnections with
// the backend.
let (kill_evt, pause_evt) = self.common.dup_eventfds();
let (kill_evt, pause_evt) = self.vu_common.virtio_common.dup_eventfds();
let mut handler = self.vu_common.activate(
mem,
@@ -352,8 +362,8 @@ impl VirtioDevice for Net {
pause_evt,
)?;
let paused = self.common.paused.clone();
let paused_sync = self.common.paused_sync.clone();
let paused = self.vu_common.virtio_common.paused.clone();
let paused_sync = self.vu_common.virtio_common.paused_sync.clone();
let mut epoll_threads = Vec::new();
spawn_virtio_thread(
@@ -371,8 +381,8 @@ impl VirtioDevice for Net {
fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
// We first must resume the virtio thread if it was paused.
if self.common.pause_evt.take().is_some() {
self.common.resume().ok()?;
if self.vu_common.virtio_common.pause_evt.take().is_some() {
self.vu_common.virtio_common.resume().ok()?;
}
if let Some(vu) = &self.vu_common.vu
@@ -382,7 +392,7 @@ impl VirtioDevice for Net {
return None;
}
if let Some(kill_evt) = self.common.kill_evt.take() {
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take() {
// Ignore the result because there is nothing we can do about it.
let _ = kill_evt.write(1);
}
@@ -390,7 +400,7 @@ impl VirtioDevice for Net {
event!("virtio-device", "reset", "id", &self.id);
// Return the interrupt
Some(self.common.interrupt_cb.take().unwrap())
Some(self.vu_common.virtio_common.interrupt_cb.take().unwrap())
}
fn shutdown(&mut self) {
@@ -408,11 +418,11 @@ impl VirtioDevice for Net {
impl Pausable for Net {
fn pause(&mut self) -> result::Result<(), MigratableError> {
self.vu_common.pause()?;
self.common.pause()
self.vu_common.virtio_common.pause()
}
fn resume(&mut self) -> result::Result<(), MigratableError> {
self.common.resume()?;
self.vu_common.virtio_common.resume()?;
if let Some(epoll_thread) = &self.epoll_thread {
epoll_thread.thread().unpark();
@@ -455,7 +465,6 @@ impl Migratable for Net {
}
fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
self.vu_common
.complete_migration(self.common.kill_evt.take())
self.vu_common.complete_migration()
}
}