diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index b5231f90d8d..dbfe4232381 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -656,9 +656,9 @@ pub(crate) mod tests { use super::*; use crate::device_manager::tests::default_device_manager; use crate::devices::virtio::block::CacheType; + use crate::devices::virtio::generated::virtio_ids; use crate::devices::virtio::rng::device::ENTROPY_DEV_ID; - use crate::devices::virtio::vsock::{TYPE_VSOCK, VSOCK_DEV_ID}; - use crate::devices::virtio::{TYPE_BALLOON, TYPE_BLOCK, TYPE_RNG}; + use crate::devices::virtio::vsock::VSOCK_DEV_ID; use crate::mmds::data_store::{Mmds, MmdsVersion}; use crate::mmds::ns::MmdsNetworkStack; use crate::utils::mib_to_bytes; @@ -855,7 +855,7 @@ pub(crate) mod tests { assert!( vmm.device_manager - .get_virtio_device(TYPE_VSOCK, &vsock_dev_id) + .get_virtio_device(virtio_ids::VIRTIO_ID_VSOCK, &vsock_dev_id) .is_some() ); } @@ -880,7 +880,7 @@ pub(crate) mod tests { assert!( vmm.device_manager - .get_virtio_device(TYPE_RNG, ENTROPY_DEV_ID) + .get_virtio_device(virtio_ids::VIRTIO_ID_RNG, ENTROPY_DEV_ID) .is_some() ); } @@ -914,7 +914,7 @@ pub(crate) mod tests { assert!( vmm.device_manager - .get_virtio_device(TYPE_BALLOON, BALLOON_DEV_ID) + .get_virtio_device(virtio_ids::VIRTIO_ID_BALLOON, BALLOON_DEV_ID) .is_some() ); } @@ -965,7 +965,7 @@ pub(crate) mod tests { assert!(cmdline_contains(&cmdline, "root=/dev/vda ro")); assert!( vmm.device_manager - .get_virtio_device(TYPE_BLOCK, drive_id.as_str()) + .get_virtio_device(virtio_ids::VIRTIO_ID_BLOCK, drive_id.as_str()) .is_some() ); } @@ -986,7 +986,7 @@ pub(crate) mod tests { assert!(cmdline_contains(&cmdline, "root=PARTUUID=0eaa91a0-01 rw")); assert!( vmm.device_manager - .get_virtio_device(TYPE_BLOCK, drive_id.as_str()) + .get_virtio_device(virtio_ids::VIRTIO_ID_BLOCK, drive_id.as_str()) .is_some() ); } @@ -1008,7 +1008,7 @@ pub(crate) mod tests { assert!(!cmdline_contains(&cmdline, "root=/dev/vda")); assert!( vmm.device_manager - .get_virtio_device(TYPE_BLOCK, drive_id.as_str()) + .get_virtio_device(virtio_ids::VIRTIO_ID_BLOCK, drive_id.as_str()) .is_some() ); } @@ -1045,17 +1045,17 @@ pub(crate) mod tests { assert!(cmdline_contains(&cmdline, "root=PARTUUID=0eaa91a0-01 rw")); assert!( vmm.device_manager - .get_virtio_device(TYPE_BLOCK, "root") + .get_virtio_device(virtio_ids::VIRTIO_ID_BLOCK, "root") .is_some() ); assert!( vmm.device_manager - .get_virtio_device(TYPE_BLOCK, "secondary") + .get_virtio_device(virtio_ids::VIRTIO_ID_BLOCK, "secondary") .is_some() ); assert!( vmm.device_manager - .get_virtio_device(TYPE_BLOCK, "third") + .get_virtio_device(virtio_ids::VIRTIO_ID_BLOCK, "third") .is_some() ); @@ -1084,7 +1084,7 @@ pub(crate) mod tests { assert!(cmdline_contains(&cmdline, "root=/dev/vda rw")); assert!( vmm.device_manager - .get_virtio_device(TYPE_BLOCK, drive_id.as_str()) + .get_virtio_device(virtio_ids::VIRTIO_ID_BLOCK, drive_id.as_str()) .is_some() ); } @@ -1105,7 +1105,7 @@ pub(crate) mod tests { assert!(cmdline_contains(&cmdline, "root=PARTUUID=0eaa91a0-01 ro")); assert!( vmm.device_manager - .get_virtio_device(TYPE_BLOCK, drive_id.as_str()) + .get_virtio_device(virtio_ids::VIRTIO_ID_BLOCK, drive_id.as_str()) .is_some() ); } @@ -1126,7 +1126,7 @@ pub(crate) mod tests { assert!(cmdline_contains(&cmdline, "root=/dev/vda rw")); assert!( vmm.device_manager - .get_virtio_device(TYPE_BLOCK, drive_id.as_str()) + .get_virtio_device(virtio_ids::VIRTIO_ID_BLOCK, drive_id.as_str()) .is_some() ); } diff --git a/src/vmm/src/device_manager/mmio.rs b/src/vmm/src/device_manager/mmio.rs index a87646b11cf..46accb637b0 100644 --- a/src/vmm/src/device_manager/mmio.rs +++ b/src/vmm/src/device_manager/mmio.rs @@ -468,7 +468,7 @@ pub(crate) mod tests { use crate::test_utils::multi_region_mem_raw; use crate::vstate::kvm::Kvm; use crate::vstate::memory::{GuestAddress, GuestMemoryMmap}; - use crate::{Vm, arch}; + use crate::{Vm, arch, impl_device_type}; const QUEUE_SIZES: &[u16] = &[64]; @@ -522,6 +522,8 @@ pub(crate) mod tests { } impl VirtioDevice for DummyDevice { + impl_device_type!(0); + fn avail_features(&self) -> u64 { 0 } @@ -532,10 +534,6 @@ pub(crate) mod tests { fn set_acked_features(&mut self, _: u64) {} - fn device_type(&self) -> u32 { - 0 - } - fn queues(&self) -> &[Queue] { &self.queues } diff --git a/src/vmm/src/device_manager/mod.rs b/src/vmm/src/device_manager/mod.rs index 5cb8a73c2ec..39485004cc7 100644 --- a/src/vmm/src/device_manager/mod.rs +++ b/src/vmm/src/device_manager/mod.rs @@ -91,7 +91,7 @@ pub enum FindDeviceError { /// Device not found DeviceNotFound, /// Internal Device error: {0} - InternalDeviceError(String), + InternalDeviceError(anyhow::Error), } #[derive(Debug)] @@ -371,27 +371,35 @@ impl DeviceManager { } /// Run fn `f()` for the virtio device matching `virtio_type` and `id`. - pub fn with_virtio_device_with_id( + pub fn try_with_virtio_device_with_id( &self, - virtio_type: u32, id: &str, f: F, - ) -> Result<(), FindDeviceError> + ) -> Result where T: VirtioDevice + 'static + Debug, - F: FnOnce(&mut T) -> Result<(), String>, + E: std::error::Error + 'static + Send + Sync, + F: FnOnce(&mut T) -> Result, { - if let Some(device) = self.get_virtio_device(virtio_type, id) { + if let Some(device) = self.get_virtio_device(T::const_device_type(), id) { let mut dev = device.lock().expect("Poisoned lock"); f(dev .as_mut_any() .downcast_mut::() .ok_or(FindDeviceError::InvalidDeviceType)?) - .map_err(FindDeviceError::InternalDeviceError)?; + .map_err(|e| FindDeviceError::InternalDeviceError(e.into())) } else { - return Err(FindDeviceError::DeviceNotFound); + Err(FindDeviceError::DeviceNotFound) } - Ok(()) + } + + /// Run fn `f()` for the virtio device matching `virtio_type` and `id`. + pub fn with_virtio_device_with_id(&self, id: &str, f: F) -> Result + where + T: VirtioDevice + 'static + Debug, + F: FnOnce(&mut T) -> R, + { + self.try_with_virtio_device_with_id(id, |dev: &mut T| Ok::(f(dev))) } } diff --git a/src/vmm/src/device_manager/pci_mngr.rs b/src/vmm/src/device_manager/pci_mngr.rs index adfde6252ad..c68b47ce83c 100644 --- a/src/vmm/src/device_manager/pci_mngr.rs +++ b/src/vmm/src/device_manager/pci_mngr.rs @@ -19,6 +19,7 @@ use crate::devices::virtio::balloon::persist::{BalloonConstructorArgs, BalloonSt use crate::devices::virtio::block::device::Block; use crate::devices::virtio::block::persist::{BlockConstructorArgs, BlockState}; use crate::devices::virtio::device::VirtioDevice; +use crate::devices::virtio::generated::virtio_ids; use crate::devices::virtio::net::Net; use crate::devices::virtio::net::persist::{NetConstructorArgs, NetState}; use crate::devices::virtio::rng::Entropy; @@ -29,8 +30,7 @@ use crate::devices::virtio::transport::pci::device::{ use crate::devices::virtio::vsock::persist::{ VsockConstructorArgs, VsockState, VsockUdsConstructorArgs, }; -use crate::devices::virtio::vsock::{TYPE_VSOCK, Vsock, VsockUnixBackend}; -use crate::devices::virtio::{TYPE_BALLOON, TYPE_BLOCK, TYPE_NET, TYPE_RNG}; +use crate::devices::virtio::vsock::{Vsock, VsockUnixBackend}; use crate::resources::VmResources; use crate::snapshot::Persist; use crate::vmm_config::mmds::MmdsConfigError; @@ -285,7 +285,7 @@ impl<'a> Persist<'a> for PciDevices { let pci_device_bdf = transport_state.pci_device_bdf.into(); match locked_virtio_dev.device_type() { - TYPE_BALLOON => { + virtio_ids::VIRTIO_ID_BALLOON => { let balloon_device = locked_virtio_dev .as_any() .downcast_ref::() @@ -300,7 +300,7 @@ impl<'a> Persist<'a> for PciDevices { transport_state, }); } - TYPE_BLOCK => { + virtio_ids::VIRTIO_ID_BLOCK => { let block_dev = locked_virtio_dev .as_mut_any() .downcast_mut::() @@ -321,7 +321,7 @@ impl<'a> Persist<'a> for PciDevices { }); } } - TYPE_NET => { + virtio_ids::VIRTIO_ID_NET => { let net_dev = locked_virtio_dev .as_mut_any() .downcast_mut::() @@ -343,7 +343,7 @@ impl<'a> Persist<'a> for PciDevices { transport_state, }) } - TYPE_VSOCK => { + virtio_ids::VIRTIO_ID_VSOCK => { let vsock_dev = locked_virtio_dev .as_mut_any() // Currently, VsockUnixBackend is the only implementation of VsockBackend. @@ -374,7 +374,7 @@ impl<'a> Persist<'a> for PciDevices { transport_state, }); } - TYPE_RNG => { + virtio_ids::VIRTIO_ID_RNG => { let rng_dev = locked_virtio_dev .as_mut_any() .downcast_mut::() diff --git a/src/vmm/src/device_manager/persist.rs b/src/vmm/src/device_manager/persist.rs index 350a392597c..eb565c2ffbc 100644 --- a/src/vmm/src/device_manager/persist.rs +++ b/src/vmm/src/device_manager/persist.rs @@ -17,12 +17,14 @@ use crate::arch::DeviceType; use crate::devices::acpi::vmgenid::{VMGenIDState, VMGenIdConstructorArgs, VmGenId, VmGenIdError}; #[cfg(target_arch = "aarch64")] use crate::devices::legacy::RTCDevice; +use crate::devices::virtio::ActivateError; use crate::devices::virtio::balloon::persist::{BalloonConstructorArgs, BalloonState}; use crate::devices::virtio::balloon::{Balloon, BalloonError}; use crate::devices::virtio::block::BlockError; use crate::devices::virtio::block::device::Block; use crate::devices::virtio::block::persist::{BlockConstructorArgs, BlockState}; use crate::devices::virtio::device::VirtioDevice; +use crate::devices::virtio::generated::virtio_ids; use crate::devices::virtio::net::Net; use crate::devices::virtio::net::persist::{ NetConstructorArgs, NetPersistError as NetError, NetState, @@ -36,10 +38,7 @@ use crate::devices::virtio::transport::mmio::{IrqTrigger, MmioTransport}; use crate::devices::virtio::vsock::persist::{ VsockConstructorArgs, VsockState, VsockUdsConstructorArgs, }; -use crate::devices::virtio::vsock::{ - TYPE_VSOCK, Vsock, VsockError, VsockUnixBackend, VsockUnixBackendError, -}; -use crate::devices::virtio::{ActivateError, TYPE_BALLOON, TYPE_BLOCK, TYPE_NET, TYPE_RNG}; +use crate::devices::virtio::vsock::{Vsock, VsockError, VsockUnixBackend, VsockUnixBackendError}; use crate::mmds::data_store::MmdsVersion; use crate::resources::{ResourcesError, VmResources}; use crate::snapshot::Persist; @@ -242,7 +241,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { let mut locked_device = mmio_transport_locked.locked_device(); match locked_device.device_type() { - TYPE_BALLOON => { + virtio_ids::VIRTIO_ID_BALLOON => { let device_state = locked_device .as_any() .downcast_ref::() @@ -256,7 +255,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { }); } // Both virtio-block and vhost-user-block share same device type. - TYPE_BLOCK => { + virtio_ids::VIRTIO_ID_BLOCK => { let block = locked_device.as_mut_any().downcast_mut::().unwrap(); if block.is_vhost_user() { warn!( @@ -274,7 +273,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { }); } } - TYPE_NET => { + virtio_ids::VIRTIO_ID_NET => { let net = locked_device.as_mut_any().downcast_mut::().unwrap(); if let (Some(mmds_ns), None) = (net.mmds_ns.as_ref(), states.mmds.as_ref()) { let mmds_guard = mmds_ns.mmds.lock().expect("Poisoned lock"); @@ -293,7 +292,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { device_info, }); } - TYPE_VSOCK => { + virtio_ids::VIRTIO_ID_VSOCK => { let vsock = locked_device .as_mut_any() // Currently, VsockUnixBackend is the only implementation of VsockBackend. @@ -322,7 +321,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { device_info, }); } - TYPE_RNG => { + virtio_ids::VIRTIO_ID_RNG => { let entropy = locked_device .as_mut_any() .downcast_mut::() diff --git a/src/vmm/src/devices/virtio/balloon/device.rs b/src/vmm/src/devices/virtio/balloon/device.rs index 4586592182c..87a82c4fa9d 100644 --- a/src/vmm/src/devices/virtio/balloon/device.rs +++ b/src/vmm/src/devices/virtio/balloon/device.rs @@ -10,9 +10,9 @@ use serde::Serialize; use timerfd::{ClockId, SetTimeFlags, TimerFd, TimerState}; use vmm_sys_util::eventfd::EventFd; +use super::super::ActivateError; use super::super::device::{DeviceState, VirtioDevice}; use super::super::queue::Queue; -use super::super::{ActivateError, TYPE_BALLOON}; use super::metrics::METRICS; use super::util::{compact_page_frame_numbers, remove_range}; use super::{ @@ -27,11 +27,13 @@ use super::{ use crate::devices::virtio::balloon::BalloonError; use crate::devices::virtio::device::ActiveState; use crate::devices::virtio::generated::virtio_config::VIRTIO_F_VERSION_1; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_BALLOON; use crate::devices::virtio::queue::InvalidAvailIdx; use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType}; use crate::logger::IncMetric; use crate::utils::u64_to_usize; use crate::vstate::memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryMmap}; +use crate::{impl_device_type, mem_size_mib}; const SIZE_OF_U32: usize = std::mem::size_of::(); const SIZE_OF_STAT: usize = std::mem::size_of::(); @@ -39,7 +41,9 @@ const SIZE_OF_STAT: usize = std::mem::size_of::(); fn mib_to_pages(amount_mib: u32) -> Result { amount_mib .checked_mul(MIB_TO_4K_PAGES) - .ok_or(BalloonError::TooManyPagesRequested) + .ok_or(BalloonError::TooMuchMemoryRequested( + u32::MAX / MIB_TO_4K_PAGES, + )) } fn pages_to_mib(amount_pages: u32) -> u32 { @@ -80,7 +84,7 @@ pub struct BalloonConfig { } /// BalloonStats holds statistics returned from the stats_queue. -#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize)] +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] pub struct BalloonStats { /// The target size of the balloon, in 4K pages. @@ -449,6 +453,12 @@ impl Balloon { /// Update the target size of the balloon. pub fn update_size(&mut self, amount_mib: u32) -> Result<(), BalloonError> { if self.is_activated() { + let mem = &self.device_state.active_state().unwrap().mem; + // The balloon cannot have a target size greater than the size of + // the guest memory. + if u64::from(amount_mib) > mem_size_mib(mem) { + return Err(BalloonError::TooMuchMemoryRequested(amount_mib)); + } self.config_space.num_pages = mib_to_pages(amount_mib)?; self.interrupt_trigger() .trigger(VirtioInterruptType::Config) @@ -503,15 +513,15 @@ impl Balloon { } /// Retrieve latest stats for the balloon device. - pub fn latest_stats(&mut self) -> Option<&BalloonStats> { + pub fn latest_stats(&mut self) -> Result { if self.stats_enabled() { self.latest_stats.target_pages = self.config_space.num_pages; self.latest_stats.actual_pages = self.config_space.actual_pages; self.latest_stats.target_mib = pages_to_mib(self.latest_stats.target_pages); self.latest_stats.actual_mib = pages_to_mib(self.latest_stats.actual_pages); - Some(&self.latest_stats) + Ok(self.latest_stats) } else { - None + Err(BalloonError::StatisticsDisabled) } } @@ -534,6 +544,8 @@ impl Balloon { } impl VirtioDevice for Balloon { + impl_device_type!(VIRTIO_ID_BALLOON); + fn avail_features(&self) -> u64 { self.avail_features } @@ -546,10 +558,6 @@ impl VirtioDevice for Balloon { self.acked_features = acked_features; } - fn device_type(&self) -> u32 { - TYPE_BALLOON - } - fn queues(&self) -> &[Queue] { &self.queues } @@ -732,7 +740,7 @@ pub(crate) mod tests { for deflate_on_oom in [true, false].iter() { for stats_interval in [0, 1].iter() { let mut balloon = Balloon::new(0, *deflate_on_oom, *stats_interval, false).unwrap(); - assert_eq!(balloon.device_type(), TYPE_BALLOON); + assert_eq!(balloon.device_type(), VIRTIO_ID_BALLOON); let features: u64 = (1u64 << VIRTIO_F_VERSION_1) | (u64::from(*deflate_on_oom) << VIRTIO_BALLOON_F_DEFLATE_ON_OOM) @@ -1072,7 +1080,7 @@ pub(crate) mod tests { free_memory: Some(0x5678), ..BalloonStats::default() }; - assert_eq!(stats, &expected_stats); + assert_eq!(stats, expected_stats); // Wait for the timer to expire, although as it is non-blocking // we could just process the timer event and it would not @@ -1149,7 +1157,7 @@ pub(crate) mod tests { let mut balloon = Balloon::new(0, true, 0, false).unwrap(); // Switch the state to active. balloon.device_state = DeviceState::Activated(ActiveState { - mem: single_region_mem(0x1), + mem: single_region_mem(32 << 20), interrupt: default_interrupt(), }); diff --git a/src/vmm/src/devices/virtio/balloon/mod.rs b/src/vmm/src/devices/virtio/balloon/mod.rs index 3f3e9346545..91de01a8393 100644 --- a/src/vmm/src/devices/virtio/balloon/mod.rs +++ b/src/vmm/src/devices/virtio/balloon/mod.rs @@ -67,8 +67,6 @@ const VIRTIO_BALLOON_S_HTLB_PGFAIL: u16 = 9; /// Balloon device related errors. #[derive(Debug, thiserror::Error, displaydoc::Display)] pub enum BalloonError { - /// No balloon device found. - DeviceNotFound, /// Device not activated yet. DeviceNotActive, /// EventFd error: {0} @@ -85,8 +83,8 @@ pub enum BalloonError { StatisticsDisabled, /// Statistics cannot be enabled/disabled after activation. StatisticsStateChange, - /// Amount of pages requested cannot fit in `u32`. - TooManyPagesRequested, + /// Requested memory should be less than {0}MiB + TooMuchMemoryRequested(u32), /// Error while processing the virt queues: {0} Queue(#[from] QueueError), /// {0} diff --git a/src/vmm/src/devices/virtio/balloon/persist.rs b/src/vmm/src/devices/virtio/balloon/persist.rs index 41e92c839c3..095ecebdfe0 100644 --- a/src/vmm/src/devices/virtio/balloon/persist.rs +++ b/src/vmm/src/devices/virtio/balloon/persist.rs @@ -10,9 +10,9 @@ use serde::{Deserialize, Serialize}; use timerfd::{SetTimeFlags, TimerState}; use super::*; -use crate::devices::virtio::TYPE_BALLOON; use crate::devices::virtio::balloon::device::{BalloonStats, ConfigSpace}; use crate::devices::virtio::device::{ActiveState, DeviceState}; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_BALLOON; use crate::devices::virtio::persist::VirtioDeviceState; use crate::devices::virtio::queue::FIRECRACKER_MAX_QUEUE_SIZE; use crate::devices::virtio::transport::VirtioInterrupt; @@ -139,7 +139,7 @@ impl Persist<'_> for Balloon { .virtio_state .build_queues_checked( &constructor_args.mem, - TYPE_BALLOON, + VIRTIO_ID_BALLOON, num_queues, FIRECRACKER_MAX_QUEUE_SIZE, ) @@ -174,7 +174,6 @@ impl Persist<'_> for Balloon { mod tests { use super::*; - use crate::devices::virtio::TYPE_BALLOON; use crate::devices::virtio::device::VirtioDevice; use crate::devices::virtio::test_utils::{default_interrupt, default_mem}; use crate::snapshot::Snapshot; @@ -201,7 +200,7 @@ mod tests { ) .unwrap(); - assert_eq!(restored_balloon.device_type(), TYPE_BALLOON); + assert_eq!(restored_balloon.device_type(), VIRTIO_ID_BALLOON); assert!(restored_balloon.restored_from_file); assert_eq!(restored_balloon.acked_features, balloon.acked_features); diff --git a/src/vmm/src/devices/virtio/block/device.rs b/src/vmm/src/devices/virtio/block/device.rs index c1fa95f7b1c..93eb56e7760 100644 --- a/src/vmm/src/devices/virtio/block/device.rs +++ b/src/vmm/src/devices/virtio/block/device.rs @@ -11,10 +11,12 @@ use super::BlockError; use super::persist::{BlockConstructorArgs, BlockState}; use super::vhost_user::device::{VhostUserBlock, VhostUserBlockConfig}; use super::virtio::device::{VirtioBlock, VirtioBlockConfig}; +use crate::devices::virtio::ActivateError; use crate::devices::virtio::device::VirtioDevice; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_BLOCK; use crate::devices::virtio::queue::{InvalidAvailIdx, Queue}; use crate::devices::virtio::transport::VirtioInterrupt; -use crate::devices::virtio::{ActivateError, TYPE_BLOCK}; +use crate::impl_device_type; use crate::rate_limiter::BucketUpdate; use crate::snapshot::Persist; use crate::vmm_config::drive::BlockDeviceConfig; @@ -131,6 +133,8 @@ impl Block { } impl VirtioDevice for Block { + impl_device_type!(VIRTIO_ID_BLOCK); + fn avail_features(&self) -> u64 { match self { Self::Virtio(b) => b.avail_features, @@ -152,10 +156,6 @@ impl VirtioDevice for Block { } } - fn device_type(&self) -> u32 { - TYPE_BLOCK - } - fn queues(&self) -> &[Queue] { match self { Self::Virtio(b) => &b.queues, diff --git a/src/vmm/src/devices/virtio/block/vhost_user/device.rs b/src/vmm/src/devices/virtio/block/vhost_user/device.rs index 1d6c2aac080..dd08b8de7c8 100644 --- a/src/vmm/src/devices/virtio/block/vhost_user/device.rs +++ b/src/vmm/src/devices/virtio/block/vhost_user/device.rs @@ -14,10 +14,12 @@ use vhost::vhost_user::message::*; use vmm_sys_util::eventfd::EventFd; use super::{NUM_QUEUES, QUEUE_SIZE, VhostUserBlockError}; +use crate::devices::virtio::ActivateError; use crate::devices::virtio::block::CacheType; use crate::devices::virtio::device::{ActiveState, DeviceState, VirtioDevice}; use crate::devices::virtio::generated::virtio_blk::{VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_RO}; use crate::devices::virtio::generated::virtio_config::VIRTIO_F_VERSION_1; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_BLOCK; use crate::devices::virtio::generated::virtio_ring::VIRTIO_RING_F_EVENT_IDX; use crate::devices::virtio::queue::Queue; use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType}; @@ -25,7 +27,7 @@ use crate::devices::virtio::vhost_user::{VhostUserHandleBackend, VhostUserHandle use crate::devices::virtio::vhost_user_metrics::{ VhostUserDeviceMetrics, VhostUserMetricsPerDevice, }; -use crate::devices::virtio::{ActivateError, TYPE_BLOCK}; +use crate::impl_device_type; use crate::logger::{IncMetric, StoreMetric, log_dev_preview_warning}; use crate::utils::u64_to_usize; use crate::vmm_config::drive::BlockDeviceConfig; @@ -286,6 +288,8 @@ impl VhostUserBlockImpl { } impl VirtioDevice for VhostUserBlockImpl { + impl_device_type!(VIRTIO_ID_BLOCK); + fn avail_features(&self) -> u64 { self.avail_features } @@ -298,10 +302,6 @@ impl VirtioDevice for VhostUserBlock self.acked_features = acked_features; } - fn device_type(&self) -> u32 { - TYPE_BLOCK - } - fn queues(&self) -> &[Queue] { &self.queues } diff --git a/src/vmm/src/devices/virtio/block/virtio/device.rs b/src/vmm/src/devices/virtio/block/virtio/device.rs index d04fd5674ea..62ebdbbf5fd 100644 --- a/src/vmm/src/devices/virtio/block/virtio/device.rs +++ b/src/vmm/src/devices/virtio/block/virtio/device.rs @@ -22,6 +22,7 @@ use vmm_sys_util::eventfd::EventFd; use super::io::async_io; use super::request::*; use super::{BLOCK_QUEUE_SIZES, SECTOR_SHIFT, SECTOR_SIZE, VirtioBlockError, io as block_io}; +use crate::devices::virtio::ActivateError; use crate::devices::virtio::block::CacheType; use crate::devices::virtio::block::virtio::metrics::{BlockDeviceMetrics, BlockMetricsPerDevice}; use crate::devices::virtio::device::{ActiveState, DeviceState, VirtioDevice}; @@ -29,10 +30,11 @@ use crate::devices::virtio::generated::virtio_blk::{ VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_RO, VIRTIO_BLK_ID_BYTES, }; use crate::devices::virtio::generated::virtio_config::VIRTIO_F_VERSION_1; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_BLOCK; use crate::devices::virtio::generated::virtio_ring::VIRTIO_RING_F_EVENT_IDX; use crate::devices::virtio::queue::{InvalidAvailIdx, Queue}; use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType}; -use crate::devices::virtio::{ActivateError, TYPE_BLOCK}; +use crate::impl_device_type; use crate::logger::{IncMetric, error, warn}; use crate::rate_limiter::{BucketUpdate, RateLimiter}; use crate::utils::u64_to_usize; @@ -581,6 +583,8 @@ impl VirtioBlock { } impl VirtioDevice for VirtioBlock { + impl_device_type!(VIRTIO_ID_BLOCK); + fn avail_features(&self) -> u64 { self.avail_features } @@ -593,10 +597,6 @@ impl VirtioDevice for VirtioBlock { self.acked_features = acked_features; } - fn device_type(&self) -> u32 { - TYPE_BLOCK - } - fn queues(&self) -> &[Queue] { &self.queues } @@ -790,7 +790,7 @@ mod tests { for engine in [FileEngineType::Sync, FileEngineType::Async] { let mut block = default_block(engine); - assert_eq!(block.device_type(), TYPE_BLOCK); + assert_eq!(block.device_type(), VIRTIO_ID_BLOCK); let features: u64 = (1u64 << VIRTIO_F_VERSION_1) | (1u64 << VIRTIO_RING_F_EVENT_IDX); diff --git a/src/vmm/src/devices/virtio/block/virtio/persist.rs b/src/vmm/src/devices/virtio/block/virtio/persist.rs index 4b6584fb5d1..3641c6adddd 100644 --- a/src/vmm/src/devices/virtio/block/virtio/persist.rs +++ b/src/vmm/src/devices/virtio/block/virtio/persist.rs @@ -9,12 +9,12 @@ use vmm_sys_util::eventfd::EventFd; use super::device::DiskProperties; use super::*; -use crate::devices::virtio::TYPE_BLOCK; use crate::devices::virtio::block::persist::BlockConstructorArgs; use crate::devices::virtio::block::virtio::device::FileEngineType; use crate::devices::virtio::block::virtio::metrics::BlockMetricsPerDevice; use crate::devices::virtio::device::{ActiveState, DeviceState}; use crate::devices::virtio::generated::virtio_blk::VIRTIO_BLK_F_RO; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_BLOCK; use crate::devices::virtio::persist::VirtioDeviceState; use crate::rate_limiter::RateLimiter; use crate::rate_limiter::persist::RateLimiterState; @@ -102,7 +102,7 @@ impl Persist<'_> for VirtioBlock { .virtio_state .build_queues_checked( &constructor_args.mem, - TYPE_BLOCK, + VIRTIO_ID_BLOCK, BLOCK_NUM_QUEUES, FIRECRACKER_MAX_QUEUE_SIZE, ) @@ -228,7 +228,7 @@ mod tests { .unwrap(); // Test that virtio specific fields are the same. - assert_eq!(restored_block.device_type(), TYPE_BLOCK); + assert_eq!(restored_block.device_type(), VIRTIO_ID_BLOCK); assert_eq!(restored_block.avail_features(), block.avail_features()); assert_eq!(restored_block.acked_features(), block.acked_features()); assert_eq!(restored_block.queues(), block.queues()); diff --git a/src/vmm/src/devices/virtio/device.rs b/src/vmm/src/devices/virtio/device.rs index ca3efc8cf2f..8d98b3f0d11 100644 --- a/src/vmm/src/devices/virtio/device.rs +++ b/src/vmm/src/devices/virtio/device.rs @@ -74,7 +74,14 @@ pub trait VirtioDevice: AsAny + Send { (self.acked_features() & (1 << feature)) != 0 } + /// The virtio device type (as a constant of the struct). + fn const_device_type() -> u32 + where + Self: Sized; + /// The virtio device type. + /// + /// It should be the same as returned by Self::const_device_type(). fn device_type(&self) -> u32; /// Returns the device queues. @@ -170,6 +177,20 @@ impl fmt::Debug for dyn VirtioDevice { } } +/// Utility to define both const_device_type and device_type with a u32 constant +#[macro_export] +macro_rules! impl_device_type { + ($const_type:expr) => { + fn const_device_type() -> u32 { + $const_type + } + + fn device_type(&self) -> u32 { + Self::const_device_type() + } + }; +} + #[cfg(test)] pub(crate) mod tests { use super::*; @@ -180,6 +201,8 @@ pub(crate) mod tests { } impl VirtioDevice for MockVirtioDevice { + impl_device_type!(0); + fn avail_features(&self) -> u64 { todo!() } @@ -192,10 +215,6 @@ pub(crate) mod tests { todo!() } - fn device_type(&self) -> u32 { - todo!() - } - fn queues(&self) -> &[Queue] { todo!() } diff --git a/src/vmm/src/devices/virtio/generated/mod.rs b/src/vmm/src/devices/virtio/generated/mod.rs index ab1a73dae7d..a9d1f08f88f 100644 --- a/src/vmm/src/devices/virtio/generated/mod.rs +++ b/src/vmm/src/devices/virtio/generated/mod.rs @@ -12,5 +12,6 @@ pub mod virtio_blk; pub mod virtio_config; +pub mod virtio_ids; pub mod virtio_net; pub mod virtio_ring; diff --git a/src/vmm/src/devices/virtio/generated/virtio_ids.rs b/src/vmm/src/devices/virtio/generated/virtio_ids.rs new file mode 100644 index 00000000000..d156fe7f7b3 --- /dev/null +++ b/src/vmm/src/devices/virtio/generated/virtio_ids.rs @@ -0,0 +1,57 @@ +// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// automatically generated by tools/bindgen.sh + +#![allow( + non_camel_case_types, + non_upper_case_globals, + dead_code, + non_snake_case, + clippy::ptr_as_ptr, + clippy::undocumented_unsafe_blocks, + missing_debug_implementations, + clippy::tests_outside_test_module, + unsafe_op_in_unsafe_fn, + clippy::redundant_static_lifetimes +)] + +pub const VIRTIO_ID_NET: u32 = 1; +pub const VIRTIO_ID_BLOCK: u32 = 2; +pub const VIRTIO_ID_CONSOLE: u32 = 3; +pub const VIRTIO_ID_RNG: u32 = 4; +pub const VIRTIO_ID_BALLOON: u32 = 5; +pub const VIRTIO_ID_IOMEM: u32 = 6; +pub const VIRTIO_ID_RPMSG: u32 = 7; +pub const VIRTIO_ID_SCSI: u32 = 8; +pub const VIRTIO_ID_9P: u32 = 9; +pub const VIRTIO_ID_MAC80211_WLAN: u32 = 10; +pub const VIRTIO_ID_RPROC_SERIAL: u32 = 11; +pub const VIRTIO_ID_CAIF: u32 = 12; +pub const VIRTIO_ID_MEMORY_BALLOON: u32 = 13; +pub const VIRTIO_ID_GPU: u32 = 16; +pub const VIRTIO_ID_CLOCK: u32 = 17; +pub const VIRTIO_ID_INPUT: u32 = 18; +pub const VIRTIO_ID_VSOCK: u32 = 19; +pub const VIRTIO_ID_CRYPTO: u32 = 20; +pub const VIRTIO_ID_SIGNAL_DIST: u32 = 21; +pub const VIRTIO_ID_PSTORE: u32 = 22; +pub const VIRTIO_ID_IOMMU: u32 = 23; +pub const VIRTIO_ID_MEM: u32 = 24; +pub const VIRTIO_ID_SOUND: u32 = 25; +pub const VIRTIO_ID_FS: u32 = 26; +pub const VIRTIO_ID_PMEM: u32 = 27; +pub const VIRTIO_ID_RPMB: u32 = 28; +pub const VIRTIO_ID_MAC80211_HWSIM: u32 = 29; +pub const VIRTIO_ID_VIDEO_ENCODER: u32 = 30; +pub const VIRTIO_ID_VIDEO_DECODER: u32 = 31; +pub const VIRTIO_ID_SCMI: u32 = 32; +pub const VIRTIO_ID_NITRO_SEC_MOD: u32 = 33; +pub const VIRTIO_ID_I2C_ADAPTER: u32 = 34; +pub const VIRTIO_ID_WATCHDOG: u32 = 35; +pub const VIRTIO_ID_CAN: u32 = 36; +pub const VIRTIO_ID_DMABUF: u32 = 37; +pub const VIRTIO_ID_PARAM_SERV: u32 = 38; +pub const VIRTIO_ID_AUDIO_POLICY: u32 = 39; +pub const VIRTIO_ID_BT: u32 = 40; +pub const VIRTIO_ID_GPIO: u32 = 41; diff --git a/src/vmm/src/devices/virtio/mod.rs b/src/vmm/src/devices/virtio/mod.rs index 0ac3b660397..1e9e3541720 100644 --- a/src/vmm/src/devices/virtio/mod.rs +++ b/src/vmm/src/devices/virtio/mod.rs @@ -46,17 +46,6 @@ mod device_status { pub const DEVICE_NEEDS_RESET: u32 = 64; } -/// Types taken from linux/virtio_ids.h. -/// Type 0 is not used by virtio. Use it as wildcard for non-virtio devices -/// Virtio net device ID. -pub const TYPE_NET: u32 = 1; -/// Virtio block device ID. -pub const TYPE_BLOCK: u32 = 2; -/// Virtio rng device ID. -pub const TYPE_RNG: u32 = 4; -/// Virtio balloon device ID. -pub const TYPE_BALLOON: u32 = 5; - /// Offset from the base MMIO address of a virtio device used by the guest to notify the device of /// queue events. pub const NOTIFY_REG_OFFSET: u32 = 0x50; diff --git a/src/vmm/src/devices/virtio/net/device.rs b/src/vmm/src/devices/virtio/net/device.rs index 0b2f3150c09..70fe5405e22 100755 --- a/src/vmm/src/devices/virtio/net/device.rs +++ b/src/vmm/src/devices/virtio/net/device.rs @@ -17,8 +17,10 @@ use log::{error, info}; use vmm_sys_util::eventfd::EventFd; use super::NET_QUEUE_MAX_SIZE; +use crate::devices::virtio::ActivateError; use crate::devices::virtio::device::{ActiveState, DeviceState, VirtioDevice}; use crate::devices::virtio::generated::virtio_config::VIRTIO_F_VERSION_1; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_NET; use crate::devices::virtio::generated::virtio_net::{ VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO, @@ -35,10 +37,10 @@ use crate::devices::virtio::net::{ }; use crate::devices::virtio::queue::{DescriptorChain, InvalidAvailIdx, Queue}; use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType}; -use crate::devices::virtio::{ActivateError, TYPE_NET}; use crate::devices::{DeviceError, report_net_event_fail}; use crate::dumbo::pdu::arp::ETH_IPV4_FRAME_LEN; use crate::dumbo::pdu::ethernet::{EthernetFrame, PAYLOAD_OFFSET}; +use crate::impl_device_type; use crate::logger::{IncMetric, METRICS}; use crate::mmds::data_store::Mmds; use crate::mmds::ns::MmdsNetworkStack; @@ -960,6 +962,8 @@ impl Net { } impl VirtioDevice for Net { + impl_device_type!(VIRTIO_ID_NET); + fn avail_features(&self) -> u64 { self.avail_features } @@ -972,10 +976,6 @@ impl VirtioDevice for Net { self.acked_features = acked_features; } - fn device_type(&self) -> u32 { - TYPE_NET - } - fn queues(&self) -> &[Queue] { &self.queues } @@ -1154,7 +1154,7 @@ pub mod tests { fn test_virtio_device_type() { let mut net = default_net(); set_mac(&mut net, MacAddr::from_str("11:22:33:44:55:66").unwrap()); - assert_eq!(net.device_type(), TYPE_NET); + assert_eq!(net.device_type(), VIRTIO_ID_NET); } #[test] diff --git a/src/vmm/src/devices/virtio/net/persist.rs b/src/vmm/src/devices/virtio/net/persist.rs index 711dc539b38..522f9c69f23 100644 --- a/src/vmm/src/devices/virtio/net/persist.rs +++ b/src/vmm/src/devices/virtio/net/persist.rs @@ -10,8 +10,8 @@ use serde::{Deserialize, Serialize}; use super::device::{Net, RxBuffers}; use super::{NET_NUM_QUEUES, NET_QUEUE_MAX_SIZE, RX_INDEX, TapError}; -use crate::devices::virtio::TYPE_NET; use crate::devices::virtio::device::{ActiveState, DeviceState}; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_NET; use crate::devices::virtio::persist::{PersistError as VirtioStateError, VirtioDeviceState}; use crate::devices::virtio::transport::VirtioInterrupt; use crate::mmds::data_store::Mmds; @@ -121,7 +121,7 @@ impl Persist<'_> for Net { net.queues = state.virtio_state.build_queues_checked( &constructor_args.mem, - TYPE_NET, + VIRTIO_ID_NET, NET_NUM_QUEUES, NET_QUEUE_MAX_SIZE, )?; @@ -179,7 +179,7 @@ mod tests { ) { Ok(restored_net) => { // Test that virtio specific fields are the same. - assert_eq!(restored_net.device_type(), TYPE_NET); + assert_eq!(restored_net.device_type(), VIRTIO_ID_NET); assert_eq!(restored_net.avail_features(), virtio_state.avail_features); assert_eq!(restored_net.acked_features(), virtio_state.acked_features); assert_eq!(restored_net.is_activated(), virtio_state.activated); diff --git a/src/vmm/src/devices/virtio/rng/device.rs b/src/vmm/src/devices/virtio/rng/device.rs index 2cf1c6bf5dd..6f488fbe217 100644 --- a/src/vmm/src/devices/virtio/rng/device.rs +++ b/src/vmm/src/devices/virtio/rng/device.rs @@ -13,13 +13,15 @@ use vmm_sys_util::eventfd::EventFd; use super::metrics::METRICS; use super::{RNG_NUM_QUEUES, RNG_QUEUE}; use crate::devices::DeviceError; +use crate::devices::virtio::ActivateError; use crate::devices::virtio::device::{ActiveState, DeviceState, VirtioDevice}; use crate::devices::virtio::generated::virtio_config::VIRTIO_F_VERSION_1; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_RNG; use crate::devices::virtio::iov_deque::IovDequeError; use crate::devices::virtio::iovec::IoVecBufferMut; use crate::devices::virtio::queue::{FIRECRACKER_MAX_QUEUE_SIZE, InvalidAvailIdx, Queue}; use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType}; -use crate::devices::virtio::{ActivateError, TYPE_RNG}; +use crate::impl_device_type; use crate::logger::{IncMetric, debug, error}; use crate::rate_limiter::{RateLimiter, TokenType}; use crate::vstate::memory::GuestMemoryMmap; @@ -252,9 +254,7 @@ impl Entropy { } impl VirtioDevice for Entropy { - fn device_type(&self) -> u32 { - TYPE_RNG - } + impl_device_type!(VIRTIO_ID_RNG); fn queues(&self) -> &[Queue] { &self.queues @@ -366,7 +366,7 @@ mod tests { #[test] fn test_device_type() { let entropy_dev = default_entropy(); - assert_eq!(entropy_dev.device_type(), TYPE_RNG); + assert_eq!(entropy_dev.device_type(), VIRTIO_ID_RNG); } #[test] diff --git a/src/vmm/src/devices/virtio/rng/persist.rs b/src/vmm/src/devices/virtio/rng/persist.rs index cb9289ecb85..5018bb40cd5 100644 --- a/src/vmm/src/devices/virtio/rng/persist.rs +++ b/src/vmm/src/devices/virtio/rng/persist.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use serde::{Deserialize, Serialize}; -use crate::devices::virtio::TYPE_RNG; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_RNG; use crate::devices::virtio::persist::{PersistError as VirtioStateError, VirtioDeviceState}; use crate::devices::virtio::queue::FIRECRACKER_MAX_QUEUE_SIZE; use crate::devices::virtio::rng::{Entropy, EntropyError, RNG_NUM_QUEUES}; @@ -56,7 +56,7 @@ impl Persist<'_> for Entropy { ) -> Result { let queues = state.virtio_state.build_queues_checked( &constructor_args.mem, - TYPE_RNG, + VIRTIO_ID_RNG, RNG_NUM_QUEUES, FIRECRACKER_MAX_QUEUE_SIZE, )?; @@ -96,7 +96,7 @@ mod tests { ) .unwrap(); - assert_eq!(restored.device_type(), TYPE_RNG); + assert_eq!(restored.device_type(), VIRTIO_ID_RNG); assert_eq!(restored.id(), ENTROPY_DEV_ID); assert!(!restored.is_activated()); assert!(!entropy.is_activated()); diff --git a/src/vmm/src/devices/virtio/transport/mmio.rs b/src/vmm/src/devices/virtio/transport/mmio.rs index 4964f837aca..ad422496f44 100644 --- a/src/vmm/src/devices/virtio/transport/mmio.rs +++ b/src/vmm/src/devices/virtio/transport/mmio.rs @@ -476,6 +476,7 @@ pub(crate) mod tests { use super::*; use crate::devices::virtio::ActivateError; use crate::devices::virtio::device_status::DEVICE_NEEDS_RESET; + use crate::impl_device_type; use crate::test_utils::single_region_mem; use crate::utils::byte_order::{read_le_u32, write_le_u32}; use crate::utils::u64_to_usize; @@ -516,6 +517,8 @@ pub(crate) mod tests { } impl VirtioDevice for DummyDevice { + impl_device_type!(123); + fn avail_features(&self) -> u64 { self.avail_features } @@ -528,10 +531,6 @@ pub(crate) mod tests { self.acked_features = acked_features; } - fn device_type(&self) -> u32 { - 123 - } - fn queues(&self) -> &[Queue] { &self.queues } diff --git a/src/vmm/src/devices/virtio/transport/pci/device.rs b/src/vmm/src/devices/virtio/transport/pci/device.rs index 038264bb417..7e3f83e66fe 100644 --- a/src/vmm/src/devices/virtio/transport/pci/device.rs +++ b/src/vmm/src/devices/virtio/transport/pci/device.rs @@ -33,12 +33,12 @@ use vmm_sys_util::eventfd::EventFd; use crate::Vm; use crate::devices::virtio::device::VirtioDevice; +use crate::devices::virtio::generated::virtio_ids; use crate::devices::virtio::queue::Queue; use crate::devices::virtio::transport::pci::common_config::{ VirtioPciCommonConfig, VirtioPciCommonConfigState, }; use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType}; -use crate::devices::virtio::{TYPE_BLOCK, TYPE_NET}; use crate::logger::{debug, error}; use crate::snapshot::Persist; use crate::utils::u64_to_usize; @@ -372,11 +372,11 @@ impl VirtioPciDevice { ) -> PciConfiguration { let pci_device_id = VIRTIO_PCI_DEVICE_ID_BASE + u16::try_from(virtio_device_type).unwrap(); let (class, subclass) = match virtio_device_type { - TYPE_NET => ( + virtio_ids::VIRTIO_ID_NET => ( PciClassCode::NetworkController, &PciNetworkControllerSubclass::EthernetController as &dyn PciSubclass, ), - TYPE_BLOCK => ( + virtio_ids::VIRTIO_ID_BLOCK => ( PciClassCode::MassStorage, &PciMassStorageSubclass::MassStorage as &dyn PciSubclass, ), diff --git a/src/vmm/src/devices/virtio/vsock/device.rs b/src/vmm/src/devices/virtio/vsock/device.rs index 43c9d4cb2ba..7fe10d158ad 100644 --- a/src/vmm/src/devices/virtio/vsock/device.rs +++ b/src/vmm/src/devices/virtio/vsock/device.rs @@ -34,10 +34,12 @@ use super::{VsockBackend, defs}; use crate::devices::virtio::ActivateError; use crate::devices::virtio::device::{ActiveState, DeviceState, VirtioDevice}; use crate::devices::virtio::generated::virtio_config::{VIRTIO_F_IN_ORDER, VIRTIO_F_VERSION_1}; +use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_VSOCK; use crate::devices::virtio::queue::{InvalidAvailIdx, Queue as VirtQueue}; use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType}; use crate::devices::virtio::vsock::VsockError; use crate::devices::virtio::vsock::metrics::METRICS; +use crate::impl_device_type; use crate::logger::IncMetric; use crate::utils::byte_order; use crate::vstate::memory::{Bytes, GuestMemoryMmap}; @@ -282,6 +284,8 @@ impl VirtioDevice for Vsock where B: VsockBackend + Debug + 'static, { + impl_device_type!(VIRTIO_ID_VSOCK); + fn avail_features(&self) -> u64 { self.avail_features } @@ -294,10 +298,6 @@ where self.acked_features = acked_features } - fn device_type(&self) -> u32 { - uapi::VIRTIO_ID_VSOCK - } - fn queues(&self) -> &[VirtQueue] { &self.queues } @@ -412,7 +412,7 @@ mod tests { (driver_features & 0xffff_ffff) as u32, (driver_features >> 32) as u32, ]; - assert_eq!(ctx.device.device_type(), uapi::VIRTIO_ID_VSOCK); + assert_eq!(ctx.device.device_type(), VIRTIO_ID_VSOCK); assert_eq!(ctx.device.avail_features_by_page(0), device_pages[0]); assert_eq!(ctx.device.avail_features_by_page(1), device_pages[1]); assert_eq!(ctx.device.avail_features_by_page(2), 0); diff --git a/src/vmm/src/devices/virtio/vsock/mod.rs b/src/vmm/src/devices/virtio/vsock/mod.rs index 859e198860b..cc9f7746580 100644 --- a/src/vmm/src/devices/virtio/vsock/mod.rs +++ b/src/vmm/src/devices/virtio/vsock/mod.rs @@ -26,7 +26,6 @@ use vm_memory::GuestMemoryError; use vmm_sys_util::epoll::EventSet; pub use self::defs::VSOCK_DEV_ID; -pub use self::defs::uapi::VIRTIO_ID_VSOCK as TYPE_VSOCK; pub use self::device::Vsock; use self::packet::{VsockPacketRx, VsockPacketTx}; pub use self::unix::{VsockUnixBackend, VsockUnixBackendError}; @@ -56,11 +55,6 @@ mod defs { pub const MAX_PKT_BUF_SIZE: u32 = 64 * 1024; pub mod uapi { - - /// Virtio vsock device ID. - /// Defined in `include/uapi/linux/virtio_ids.h`. - pub const VIRTIO_ID_VSOCK: u32 = 19; - /// Vsock packet operation IDs. /// Defined in `/include/uapi/linux/virtio_vsock.h`. /// diff --git a/src/vmm/src/devices/virtio/vsock/persist.rs b/src/vmm/src/devices/virtio/vsock/persist.rs index 14d7984ce54..b8dcbd9113c 100644 --- a/src/vmm/src/devices/virtio/vsock/persist.rs +++ b/src/vmm/src/devices/virtio/vsock/persist.rs @@ -10,10 +10,10 @@ use serde::{Deserialize, Serialize}; use super::*; use crate::devices::virtio::device::{ActiveState, DeviceState}; +use crate::devices::virtio::generated::virtio_ids::{self, VIRTIO_ID_VSOCK}; use crate::devices::virtio::persist::VirtioDeviceState; use crate::devices::virtio::queue::FIRECRACKER_MAX_QUEUE_SIZE; use crate::devices::virtio::transport::VirtioInterrupt; -use crate::devices::virtio::vsock::TYPE_VSOCK; use crate::snapshot::Persist; use crate::vstate::memory::GuestMemoryMmap; @@ -112,7 +112,7 @@ where .virtio_state .build_queues_checked( &constructor_args.mem, - TYPE_VSOCK, + VIRTIO_ID_VSOCK, defs::VSOCK_NUM_QUEUES, FIRECRACKER_MAX_QUEUE_SIZE, ) @@ -195,7 +195,7 @@ pub(crate) mod tests { ) .unwrap(); - assert_eq!(restored_device.device_type(), uapi::VIRTIO_ID_VSOCK); + assert_eq!(restored_device.device_type(), VIRTIO_ID_VSOCK); assert_eq!(restored_device.avail_features_by_page(0), device_pages[0]); assert_eq!(restored_device.avail_features_by_page(1), device_pages[1]); assert_eq!(restored_device.avail_features_by_page(2), 0); diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index 4bb0a064799..c3b2410dfe1 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -134,12 +134,9 @@ use vstate::kvm::Kvm; use vstate::vcpu::{self, StartThreadedError, VcpuSendEventError}; use crate::cpu_config::templates::CpuConfiguration; -use crate::devices::virtio::balloon::{ - BALLOON_DEV_ID, Balloon, BalloonConfig, BalloonError, BalloonStats, -}; +use crate::devices::virtio::balloon::{BALLOON_DEV_ID, Balloon, BalloonConfig, BalloonStats}; use crate::devices::virtio::block::device::Block; use crate::devices::virtio::net::Net; -use crate::devices::virtio::{TYPE_BALLOON, TYPE_BLOCK, TYPE_NET}; use crate::logger::{METRICS, MetricsError, error, info, warn}; use crate::persist::{MicrovmState, MicrovmStateError, VmInfo}; use crate::rate_limiter::BucketUpdate; @@ -516,10 +513,8 @@ impl Vmm { path_on_host: String, ) -> Result<(), VmmError> { self.device_manager - .with_virtio_device_with_id(TYPE_BLOCK, drive_id, |block: &mut Block| { - block - .update_disk_image(path_on_host) - .map_err(|err| err.to_string()) + .try_with_virtio_device_with_id(drive_id, |block: &mut Block| { + block.update_disk_image(path_on_host) }) .map_err(VmmError::FindDeviceError) } @@ -532,10 +527,8 @@ impl Vmm { rl_ops: BucketUpdate, ) -> Result<(), VmmError> { self.device_manager - .with_virtio_device_with_id(TYPE_BLOCK, drive_id, |block: &mut Block| { - block - .update_rate_limiter(rl_bytes, rl_ops) - .map_err(|err| err.to_string()) + .try_with_virtio_device_with_id(drive_id, |block: &mut Block| { + block.update_rate_limiter(rl_bytes, rl_ops) }) .map_err(VmmError::FindDeviceError) } @@ -543,9 +536,7 @@ impl Vmm { /// Updates the rate limiter parameters for block device with `drive_id` id. pub fn update_vhost_user_block_config(&mut self, drive_id: &str) -> Result<(), VmmError> { self.device_manager - .with_virtio_device_with_id(TYPE_BLOCK, drive_id, |block: &mut Block| { - block.update_config().map_err(|err| err.to_string()) - }) + .try_with_virtio_device_with_id(drive_id, |block: &mut Block| block.update_config()) .map_err(VmmError::FindDeviceError) } @@ -559,105 +550,45 @@ impl Vmm { tx_ops: BucketUpdate, ) -> Result<(), VmmError> { self.device_manager - .with_virtio_device_with_id(TYPE_NET, net_id, |net: &mut Net| { - net.patch_rate_limiters(rx_bytes, rx_ops, tx_bytes, tx_ops); - Ok(()) + .with_virtio_device_with_id(net_id, |net: &mut Net| { + net.patch_rate_limiters(rx_bytes, rx_ops, tx_bytes, tx_ops) }) .map_err(VmmError::FindDeviceError) } /// Returns a reference to the balloon device if present. - pub fn balloon_config(&self) -> Result { - if let Some(virtio_device) = self - .device_manager - .get_virtio_device(TYPE_BALLOON, BALLOON_DEV_ID) - { - let config = virtio_device - .lock() - .expect("Poisoned lock") - .as_mut_any() - .downcast_mut::() - .unwrap() - .config(); - - Ok(config) - } else { - Err(BalloonError::DeviceNotFound) - } + pub fn balloon_config(&self) -> Result { + self.device_manager + .with_virtio_device_with_id(BALLOON_DEV_ID, |dev: &mut Balloon| dev.config()) + .map_err(VmmError::FindDeviceError) } /// Returns the latest balloon statistics if they are enabled. - pub fn latest_balloon_stats(&self) -> Result { - if let Some(virtio_device) = self - .device_manager - .get_virtio_device(TYPE_BALLOON, BALLOON_DEV_ID) - { - let latest_stats = virtio_device - .lock() - .expect("Poisoned lock") - .as_mut_any() - .downcast_mut::() - .unwrap() - .latest_stats() - .ok_or(BalloonError::StatisticsDisabled) - .cloned()?; - - Ok(latest_stats) - } else { - Err(BalloonError::DeviceNotFound) - } + pub fn latest_balloon_stats(&self) -> Result { + self.device_manager + .try_with_virtio_device_with_id(BALLOON_DEV_ID, |dev: &mut Balloon| dev.latest_stats()) + .map_err(VmmError::FindDeviceError) } /// Updates configuration for the balloon device target size. - pub fn update_balloon_config(&mut self, amount_mib: u32) -> Result<(), BalloonError> { - // The balloon cannot have a target size greater than the size of - // the guest memory. - if u64::from(amount_mib) > mem_size_mib(self.vm.guest_memory()) { - return Err(BalloonError::TooManyPagesRequested); - } - - if let Some(virtio_device) = self - .device_manager - .get_virtio_device(TYPE_BALLOON, BALLOON_DEV_ID) - { - { - virtio_device - .lock() - .expect("Poisoned lock") - .as_mut_any() - .downcast_mut::() - .unwrap() - .update_size(amount_mib)?; - - Ok(()) - } - } else { - Err(BalloonError::DeviceNotFound) - } + pub fn update_balloon_config(&mut self, amount_mib: u32) -> Result<(), VmmError> { + self.device_manager + .try_with_virtio_device_with_id(BALLOON_DEV_ID, |dev: &mut Balloon| { + dev.update_size(amount_mib) + }) + .map_err(VmmError::FindDeviceError) } /// Updates configuration for the balloon device as described in `balloon_stats_update`. pub fn update_balloon_stats_config( &mut self, stats_polling_interval_s: u16, - ) -> Result<(), BalloonError> { - if let Some(virtio_device) = self - .device_manager - .get_virtio_device(TYPE_BALLOON, BALLOON_DEV_ID) - { - { - virtio_device - .lock() - .expect("Poisoned lock") - .as_mut_any() - .downcast_mut::() - .unwrap() - .update_stats_polling_interval(stats_polling_interval_s)?; - } - Ok(()) - } else { - Err(BalloonError::DeviceNotFound) - } + ) -> Result<(), VmmError> { + self.device_manager + .try_with_virtio_device_with_id(BALLOON_DEV_ID, |dev: &mut Balloon| { + dev.update_stats_polling_interval(stats_polling_interval_s) + }) + .map_err(VmmError::FindDeviceError) } /// Signals Vmm to stop and exit. diff --git a/src/vmm/src/rpc_interface.rs b/src/vmm/src/rpc_interface.rs index 85aab1af826..8f2ff6b7740 100644 --- a/src/vmm/src/rpc_interface.rs +++ b/src/vmm/src/rpc_interface.rs @@ -131,6 +131,8 @@ pub enum VmmAction { pub enum VmmActionError { /// Balloon config error: {0} BalloonConfig(#[from] BalloonConfigError), + /// Balloon update error: {0} + BalloonUpdate(VmmError), /// Boot source error: {0} BootSource(#[from] BootSourceConfigError), /// Create snapshot error: {0} @@ -637,14 +639,14 @@ impl RuntimeApiController { .expect("Poisoned lock") .balloon_config() .map(|state| VmmData::BalloonConfig(BalloonDeviceConfig::from(state))) - .map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))), + .map_err(VmmActionError::InternalVmm), GetBalloonStats => self .vmm .lock() .expect("Poisoned lock") .latest_balloon_stats() .map(VmmData::BalloonStats) - .map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))), + .map_err(VmmActionError::InternalVmm), GetFullVmConfig => Ok(VmmData::FullVmConfig((&self.vm_resources).into())), GetMMDS => self.get_mmds(), GetVmMachineConfig => Ok(VmmData::MachineConfiguration( @@ -668,14 +670,14 @@ impl RuntimeApiController { .expect("Poisoned lock") .update_balloon_config(balloon_update.amount_mib) .map(|_| VmmData::Empty) - .map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))), + .map_err(VmmActionError::BalloonUpdate), UpdateBalloonStatistics(balloon_stats_update) => self .vmm .lock() .expect("Poisoned lock") .update_balloon_stats_config(balloon_stats_update.stats_polling_interval_s) .map(|_| VmmData::Empty) - .map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))), + .map_err(VmmActionError::BalloonUpdate), UpdateBlockDevice(new_cfg) => self.update_block_device(new_cfg), UpdateNetworkInterface(netif_update) => self.update_net_rate_limiters(netif_update), diff --git a/src/vmm/src/vmm_config/balloon.rs b/src/vmm/src/vmm_config/balloon.rs index 6ac2fb34ecf..83d419c49db 100644 --- a/src/vmm/src/vmm_config/balloon.rs +++ b/src/vmm/src/vmm_config/balloon.rs @@ -16,18 +16,10 @@ type MutexBalloon = Arc>; pub enum BalloonConfigError { /// No balloon device found. DeviceNotFound, - /// Device is inactive, check if balloon driver is enabled in guest kernel. - DeviceNotActive, - /// Cannot enable/disable the statistics after boot. - InvalidStatsUpdate, /// Amount of pages requested is too large. TooManyPagesRequested, - /// Statistics for the balloon device are not enabled - StatsNotFound, /// Error creating the balloon device: {0} CreateFailure(crate::devices::virtio::balloon::BalloonError), - /// Error updating the balloon device configuration: {0} - UpdateFailure(std::io::Error), /// Firecracker's huge pages support is incompatible with memory ballooning. HugePages, } diff --git a/tools/bindgen.sh b/tools/bindgen.sh index fdf55caff7e..e2529375285 100755 --- a/tools/bindgen.sh +++ b/tools/bindgen.sh @@ -100,6 +100,11 @@ fc-bindgen \ --allowlist-type "virtio_net_hdr_v1" \ "$INCLUDE/linux/virtio_net.h" >src/vmm/src/devices/virtio/generated/virtio_net.rs +info "BINDGEN virtio_ids.h" +fc-bindgen \ + --allowlist-var "VIRTIO_ID.*" \ + "$INCLUDE/linux/virtio_ids.h" >src/vmm/src/devices/virtio/generated/virtio_ids.rs + info "BINDGEN prctl.h" fc-bindgen \ --allowlist-var "PR_.*" \