diff --git a/src/main.rs b/src/main.rs index 69ea90c6d..d74b32da3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -236,6 +236,13 @@ fn create_app<'a, 'b>( .min_values(1) .group("vm-config"), ) + .arg( + Arg::with_name("watchdog") + .long("watchdog") + .help("Enable virtio-watchdog") + .takes_value(false) + .group("vm-config"), + ) .arg( Arg::with_name("v") .short("v") @@ -593,6 +600,7 @@ mod unit_tests { #[cfg(target_arch = "x86_64")] sgx_epc: None, numa: None, + watchdog: false, }; aver_eq!(tb, expected_vm_config, result_vm_config); diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml index e609adc0a..998e586da 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml @@ -439,6 +439,9 @@ components: iommu: type: boolean default: false + watchdog: + type: boolean + default: false description: Virtual machine configuration CpuTopology: diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 636719595..cf50dc61c 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -193,6 +193,7 @@ pub struct VmParams<'a> { #[cfg(target_arch = "x86_64")] pub sgx_epc: Option>, pub numa: Option>, + pub watchdog: bool, } impl<'a> VmParams<'a> { @@ -218,6 +219,7 @@ impl<'a> VmParams<'a> { #[cfg(target_arch = "x86_64")] let sgx_epc: Option> = args.values_of("sgx-epc").map(|x| x.collect()); let numa: Option> = args.values_of("numa").map(|x| x.collect()); + let watchdog = args.is_present("watchdog"); VmParams { cpus, @@ -238,6 +240,7 @@ impl<'a> VmParams<'a> { #[cfg(target_arch = "x86_64")] sgx_epc, numa, + watchdog, } } } @@ -1401,6 +1404,8 @@ pub struct VmConfig { #[cfg(target_arch = "x86_64")] pub sgx_epc: Option>, pub numa: Option>, + #[serde(default)] + pub watchdog: bool, } impl VmConfig { @@ -1608,6 +1613,7 @@ impl VmConfig { #[cfg(target_arch = "x86_64")] sgx_epc, numa, + watchdog: vm_params.watchdog, }; config.validate().map_err(Error::Validation)?; Ok(config) @@ -2187,6 +2193,7 @@ mod tests { #[cfg(target_arch = "x86_64")] sgx_epc: None, numa: None, + watchdog: false, }; assert!(valid_config.validate().is_ok()); diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index b3adc3861..85c6be252 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -110,6 +110,7 @@ const NET_DEVICE_NAME_PREFIX: &str = "_net"; const PMEM_DEVICE_NAME_PREFIX: &str = "_pmem"; const RNG_DEVICE_NAME: &str = "_rng"; const VSOCK_DEVICE_NAME_PREFIX: &str = "_vsock"; +const WATCHDOG_DEVICE_NAME: &str = "_watchdog"; const IOMMU_DEVICE_NAME: &str = "_iommu"; @@ -166,6 +167,9 @@ pub enum DeviceManagerError { /// Cannot create virtio-balloon device CreateVirtioBalloon(io::Error), + /// Cannot create virtio-watchdog device + CreateVirtioWatchdog(io::Error), + /// Failed parsing disk image format DetectImageType(qcow::Error), @@ -765,8 +769,6 @@ pub struct DeviceManager { #[cfg(feature = "acpi")] exit_evt: EventFd, - // Reset event - #[cfg(target_arch = "x86_64")] reset_evt: EventFd, #[cfg(target_arch = "aarch64")] @@ -787,7 +789,7 @@ impl DeviceManager { config: Arc>, memory_manager: Arc>, _exit_evt: &EventFd, - #[cfg_attr(target_arch = "aarch64", allow(unused_variables))] reset_evt: &EventFd, + reset_evt: &EventFd, vmm_path: PathBuf, seccomp_action: SeccompAction, #[cfg(feature = "acpi")] numa_nodes: NumaNodes, @@ -842,7 +844,6 @@ impl DeviceManager { device_tree, #[cfg(feature = "acpi")] exit_evt: _exit_evt.try_clone().map_err(DeviceManagerError::EventFd)?, - #[cfg(target_arch = "x86_64")] reset_evt: reset_evt.try_clone().map_err(DeviceManagerError::EventFd)?, #[cfg(target_arch = "aarch64")] id_to_dev_info: HashMap::new(), @@ -1563,6 +1564,9 @@ impl DeviceManager { // Add virtio-balloon if required devices.append(&mut self.make_virtio_balloon_devices()?); + // Add virtio-watchdog device + devices.append(&mut self.make_virtio_watchdog_devices()?); + Ok(devices) } @@ -2468,6 +2472,39 @@ impl DeviceManager { Ok(devices) } + fn make_virtio_watchdog_devices( + &mut self, + ) -> DeviceManagerResult> { + let mut devices = Vec::new(); + + if !self.config.lock().unwrap().watchdog { + return Ok(devices); + } + + let id = String::from(WATCHDOG_DEVICE_NAME); + + let virtio_watchdog_device = Arc::new(Mutex::new( + virtio_devices::Watchdog::new( + id.clone(), + self.reset_evt.try_clone().unwrap(), + self.seccomp_action.clone(), + ) + .map_err(DeviceManagerError::CreateVirtioWatchdog)?, + )); + devices.push(( + Arc::clone(&virtio_watchdog_device) as VirtioDeviceArc, + false, + id.clone(), + )); + + self.device_tree + .lock() + .unwrap() + .insert(id.clone(), device_node!(id, virtio_watchdog_device)); + + Ok(devices) + } + fn next_device_name(&mut self, prefix: &str) -> DeviceManagerResult { let start_id = self.device_id_cnt; loop { diff --git a/vmm/src/seccomp_filters.rs b/vmm/src/seccomp_filters.rs index cc9ed3689..3a208f564 100644 --- a/vmm/src/seccomp_filters.rs +++ b/vmm/src/seccomp_filters.rs @@ -367,6 +367,8 @@ fn vmm_thread_rules() -> Result, Error> { allow_syscall(libc::SYS_stat), allow_syscall(libc::SYS_statx), allow_syscall(libc::SYS_tgkill), + allow_syscall(libc::SYS_timerfd_create), + allow_syscall(libc::SYS_timerfd_settime), allow_syscall(libc::SYS_tkill), allow_syscall_if( libc::SYS_umask, @@ -459,6 +461,8 @@ fn vcpu_thread_rules() -> Result, Error> { allow_syscall(libc::SYS_stat), allow_syscall(libc::SYS_statx), allow_syscall(libc::SYS_tgkill), + allow_syscall(libc::SYS_timerfd_create), + allow_syscall(libc::SYS_timerfd_settime), allow_syscall(libc::SYS_tkill), #[cfg(target_arch = "x86_64")] allow_syscall(libc::SYS_unlink),