mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d530569ac2 | ||
|
|
75956e64ec | ||
|
|
ae646c2a00 | ||
|
|
04d3e5bbf5 | ||
|
|
cbe972659c | ||
|
|
1e4e03d110 | ||
|
|
4876f7550d | ||
|
|
c0146e3ef1 | ||
|
|
77a205881b | ||
|
|
321421c53e | ||
|
|
48a87e699d | ||
|
|
147a800d5d | ||
|
|
eaf8cbd47d | ||
|
|
9d24e862eb | ||
|
|
11324ac21c | ||
|
|
ce75865e2c |
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -179,7 +179,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "31.0.0"
|
||||
version = "31.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
@@ -545,8 +545,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kvm-ioctls"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8f8dc9c1896e5f144ec5d07169bc29f39a047686d29585a91f30489abfaeb6b"
|
||||
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#23a3bb045a467e60bb00328a0b13cea13b5815d0"
|
||||
dependencies = [
|
||||
"kvm-bindings",
|
||||
"libc",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloud-hypervisor"
|
||||
version = "31.0.0"
|
||||
version = "31.1.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
default-run = "cloud-hypervisor"
|
||||
@@ -52,6 +52,7 @@ vm-memory = "0.10.0"
|
||||
# List of patched crates
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
|
||||
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -330,7 +330,7 @@ impl KvmVm {
|
||||
Ok(VfioDeviceFd::new_from_kvm(device_fd))
|
||||
}
|
||||
/// Checks if a particular `Cap` is available.
|
||||
fn check_extension(&self, c: Cap) -> bool {
|
||||
pub fn check_extension(&self, c: Cap) -> bool {
|
||||
self.fd.check_extension(c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
- [v31.1](#v311)
|
||||
- [v31.0](#v310)
|
||||
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
|
||||
- [Update Reference Kernel to 6.2](#update-reference-kernel-to-62)
|
||||
@@ -276,6 +277,16 @@
|
||||
- [Unit testing](#unit-testing)
|
||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||
|
||||
# v31.1
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Ignore and warn TAP FDs sent via the HTTP request body (#5350)
|
||||
* Properly preserve and close valid FDs for TAP devices (#5373)
|
||||
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
|
||||
* Only touch the tty flags if it's being used (#5343)
|
||||
* Fix seccomp filter lists for vhost-user devices (#5361)
|
||||
|
||||
# v31.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
|
||||
10
src/main.rs
10
src/main.rs
@@ -21,7 +21,6 @@ use thiserror::Error;
|
||||
use vmm::config;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::signal::block_signal;
|
||||
use vmm_sys_util::terminal::Terminal;
|
||||
|
||||
#[cfg(feature = "dhat-heap")]
|
||||
#[global_allocator]
|
||||
@@ -586,14 +585,6 @@ fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
// SAFETY: trivially safe
|
||||
let on_tty = unsafe { libc::isatty(libc::STDIN_FILENO) } != 0;
|
||||
if on_tty {
|
||||
// Don't forget to set the terminal in canonical mode
|
||||
// before to exit.
|
||||
std::io::stdin().lock().set_canon_mode().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "dhat-heap")]
|
||||
drop(_profiler);
|
||||
|
||||
@@ -731,6 +722,7 @@ mod unit_tests {
|
||||
gdb: false,
|
||||
platform: None,
|
||||
tpm: None,
|
||||
preserved_fds: None,
|
||||
};
|
||||
|
||||
assert_eq!(expected_vm_config, result_vm_config);
|
||||
|
||||
@@ -6238,6 +6238,18 @@ mod common_parallel {
|
||||
.unwrap_or_default(),
|
||||
2
|
||||
);
|
||||
|
||||
guest.reboot_linux(0, None);
|
||||
|
||||
assert_eq!(
|
||||
guest
|
||||
.ssh_command("ip -o link | wc -l")
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap_or_default(),
|
||||
2
|
||||
);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
|
||||
@@ -151,6 +151,7 @@ fn virtio_rng_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
|
||||
fn virtio_vhost_fs_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_clock_nanosleep, vec![]),
|
||||
(libc::SYS_connect, vec![]),
|
||||
(libc::SYS_nanosleep, vec![]),
|
||||
(libc::SYS_pread64, vec![]),
|
||||
@@ -170,8 +171,11 @@ fn virtio_vhost_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_accept4, vec![]),
|
||||
(libc::SYS_bind, vec![]),
|
||||
(libc::SYS_clock_nanosleep, vec![]),
|
||||
(libc::SYS_connect, vec![]),
|
||||
(libc::SYS_getcwd, vec![]),
|
||||
(libc::SYS_listen, vec![]),
|
||||
(libc::SYS_nanosleep, vec![]),
|
||||
(libc::SYS_recvmsg, vec![]),
|
||||
(libc::SYS_sendmsg, vec![]),
|
||||
(libc::SYS_sendto, vec![]),
|
||||
@@ -184,7 +188,14 @@ fn virtio_vhost_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
}
|
||||
|
||||
fn virtio_vhost_block_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![]
|
||||
vec![
|
||||
(libc::SYS_clock_nanosleep, vec![]),
|
||||
(libc::SYS_connect, vec![]),
|
||||
(libc::SYS_nanosleep, vec![]),
|
||||
(libc::SYS_recvmsg, vec![]),
|
||||
(libc::SYS_sendmsg, vec![]),
|
||||
(libc::SYS_socket, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn create_vsock_ioctl_seccomp_rule() -> Vec<SeccompRule> {
|
||||
|
||||
@@ -13,7 +13,7 @@ pub mod protocol;
|
||||
|
||||
/// Global VMM version for versioning
|
||||
const MAJOR_VERSION: u16 = 31;
|
||||
const MINOR_VERSION: u16 = 0;
|
||||
const MINOR_VERSION: u16 = 1;
|
||||
const VMM_VERSION: u16 = MAJOR_VERSION << 12 | MINOR_VERSION & 0b1111;
|
||||
|
||||
pub trait VersionMapped {
|
||||
|
||||
@@ -105,6 +105,10 @@ impl EndpointHandler for VmActionHandler {
|
||||
),
|
||||
AddNet(_) => {
|
||||
let mut net_cfg: NetConfig = serde_json::from_slice(body.raw())?;
|
||||
if net_cfg.fds.is_some() {
|
||||
warn!("Ignoring FDs sent via the HTTP request body");
|
||||
net_cfg.fds = None;
|
||||
}
|
||||
// Update network config with optional files that might have
|
||||
// been sent through control message.
|
||||
if !files.is_empty() {
|
||||
|
||||
@@ -1134,38 +1134,6 @@ impl NetConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for NetConfig {
|
||||
fn clone(&self) -> Self {
|
||||
NetConfig {
|
||||
tap: self.tap.clone(),
|
||||
vhost_socket: self.vhost_socket.clone(),
|
||||
id: self.id.clone(),
|
||||
fds: self
|
||||
.fds
|
||||
.as_ref()
|
||||
// SAFETY: We have been handed these FDs through the API
|
||||
.map(|fds| fds.iter().map(|fd| unsafe { libc::dup(*fd) }).collect()),
|
||||
..*self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for NetConfig {
|
||||
fn drop(&mut self) {
|
||||
if let Some(mut fds) = self.fds.take() {
|
||||
for fd in fds.drain(..) {
|
||||
// Skip reserved FDs
|
||||
if fd <= 2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// SAFETY: Safe as the fd was given to the config by the API
|
||||
unsafe { libc::close(fd) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RngConfig {
|
||||
pub fn parse(rng: &str) -> Result<Self> {
|
||||
let mut parser = OptionParser::new();
|
||||
@@ -2125,23 +2093,83 @@ impl VmConfig {
|
||||
gdb,
|
||||
platform,
|
||||
tpm,
|
||||
preserved_fds: None,
|
||||
};
|
||||
config.validate().map_err(Error::Validation)?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// To use this safely, the caller must guarantee that the input
|
||||
/// fds are all valid.
|
||||
pub unsafe fn add_preserved_fds(&mut self, mut fds: Vec<i32>) {
|
||||
if fds.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(preserved_fds) = &self.preserved_fds {
|
||||
fds.append(&mut preserved_fds.clone());
|
||||
}
|
||||
|
||||
self.preserved_fds = Some(fds);
|
||||
}
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
pub fn is_tdx_enabled(&self) -> bool {
|
||||
self.platform.as_ref().map(|p| p.tdx).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for VmConfig {
|
||||
fn clone(&self) -> Self {
|
||||
VmConfig {
|
||||
cpus: self.cpus.clone(),
|
||||
memory: self.memory.clone(),
|
||||
payload: self.payload.clone(),
|
||||
disks: self.disks.clone(),
|
||||
net: self.net.clone(),
|
||||
rng: self.rng.clone(),
|
||||
balloon: self.balloon.clone(),
|
||||
fs: self.fs.clone(),
|
||||
pmem: self.pmem.clone(),
|
||||
serial: self.serial.clone(),
|
||||
console: self.console.clone(),
|
||||
devices: self.devices.clone(),
|
||||
user_devices: self.user_devices.clone(),
|
||||
vdpa: self.vdpa.clone(),
|
||||
vsock: self.vsock.clone(),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
sgx_epc: self.sgx_epc.clone(),
|
||||
numa: self.numa.clone(),
|
||||
platform: self.platform.clone(),
|
||||
tpm: self.tpm.clone(),
|
||||
preserved_fds: self
|
||||
.preserved_fds
|
||||
.as_ref()
|
||||
// SAFETY: FFI call with valid FDs
|
||||
.map(|fds| fds.iter().map(|fd| unsafe { libc::dup(*fd) }).collect()),
|
||||
..*self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VmConfig {
|
||||
fn drop(&mut self) {
|
||||
if let Some(mut fds) = self.preserved_fds.take() {
|
||||
for fd in fds.drain(..) {
|
||||
// SAFETY: FFI call with valid FDs
|
||||
unsafe { libc::close(fd) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{fs::File, os::fd::AsRawFd};
|
||||
|
||||
use super::*;
|
||||
use net_util::MacAddr;
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
#[test]
|
||||
fn test_cpu_parsing() -> Result<()> {
|
||||
@@ -2361,10 +2389,6 @@ mod tests {
|
||||
NetConfig {
|
||||
mac: MacAddr::parse_str("de:ad:be:ef:12:34").unwrap(),
|
||||
host_mac: Some(MacAddr::parse_str("12:34:de:ad:be:ef").unwrap()),
|
||||
fds: None,
|
||||
id: None,
|
||||
tap: None,
|
||||
vhost_socket: None,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
@@ -2375,9 +2399,6 @@ mod tests {
|
||||
mac: MacAddr::parse_str("de:ad:be:ef:12:34").unwrap(),
|
||||
host_mac: Some(MacAddr::parse_str("12:34:de:ad:be:ef").unwrap()),
|
||||
id: Some("mynet0".to_owned()),
|
||||
fds: None,
|
||||
tap: None,
|
||||
vhost_socket: None,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
@@ -2392,9 +2413,6 @@ mod tests {
|
||||
tap: Some("tap0".to_owned()),
|
||||
ip: "192.168.100.1".parse().unwrap(),
|
||||
mask: "255.255.255.128".parse().unwrap(),
|
||||
fds: None,
|
||||
id: None,
|
||||
vhost_socket: None,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
@@ -2408,9 +2426,6 @@ mod tests {
|
||||
host_mac: Some(MacAddr::parse_str("12:34:de:ad:be:ef").unwrap()),
|
||||
vhost_user: true,
|
||||
vhost_socket: Some("/tmp/sock".to_owned()),
|
||||
fds: None,
|
||||
id: None,
|
||||
tap: None,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
@@ -2423,31 +2438,18 @@ mod tests {
|
||||
num_queues: 4,
|
||||
queue_size: 1024,
|
||||
iommu: true,
|
||||
fds: None,
|
||||
id: None,
|
||||
tap: None,
|
||||
vhost_socket: None,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
// SAFETY: Safe as the file was just opened
|
||||
let fd1 = unsafe { libc::dup(File::open("/dev/null").unwrap().as_raw_fd()) };
|
||||
// SAFETY: Safe as the file was just opened
|
||||
let fd2 = unsafe { libc::dup(File::open("/dev/null").unwrap().as_raw_fd()) };
|
||||
|
||||
assert_eq!(
|
||||
&format!(
|
||||
"{:?}",
|
||||
NetConfig::parse(&format!(
|
||||
"mac=de:ad:be:ef:12:34,fd=[{fd1},{fd2}],num_queues=4"
|
||||
))?
|
||||
),
|
||||
&format!("NetConfig {{ tap: None, ip: 192.168.249.1, mask: 255.255.255.0, \
|
||||
mac: MacAddr {{ bytes: [222, 173, 190, 239, 18, 52] }}, host_mac: None, mtu: None, \
|
||||
iommu: false, num_queues: 4, queue_size: 256, vhost_user: false, vhost_socket: None, \
|
||||
vhost_mode: Client, id: None, fds: Some([{fd1}, {fd2}]), \
|
||||
rate_limiter_config: None, pci_segment: 0, offload_tso: true, offload_ufo: true, offload_csum: true }}")
|
||||
NetConfig::parse("mac=de:ad:be:ef:12:34,fd=[3,7],num_queues=4")?,
|
||||
NetConfig {
|
||||
mac: MacAddr::parse_str("de:ad:be:ef:12:34").unwrap(),
|
||||
fds: Some(vec![3, 7]),
|
||||
num_queues: 4,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -2774,6 +2776,7 @@ mod tests {
|
||||
gdb: false,
|
||||
platform: None,
|
||||
tpm: None,
|
||||
preserved_fds: None,
|
||||
};
|
||||
|
||||
assert!(valid_config.validate().is_ok());
|
||||
@@ -2868,10 +2871,6 @@ mod tests {
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.net = Some(vec![NetConfig {
|
||||
vhost_user: true,
|
||||
fds: None,
|
||||
id: None,
|
||||
tap: None,
|
||||
vhost_socket: None,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert_eq!(
|
||||
@@ -2883,9 +2882,6 @@ mod tests {
|
||||
still_valid_config.net = Some(vec![NetConfig {
|
||||
vhost_user: true,
|
||||
vhost_socket: Some("/path/to/sock".to_owned()),
|
||||
fds: None,
|
||||
id: None,
|
||||
tap: None,
|
||||
..Default::default()
|
||||
}]);
|
||||
still_valid_config.memory.shared = true;
|
||||
@@ -2894,9 +2890,6 @@ mod tests {
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.net = Some(vec![NetConfig {
|
||||
fds: Some(vec![0]),
|
||||
id: None,
|
||||
tap: None,
|
||||
vhost_socket: None,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert_eq!(
|
||||
@@ -2907,10 +2900,6 @@ mod tests {
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.net = Some(vec![NetConfig {
|
||||
offload_csum: false,
|
||||
fds: None,
|
||||
id: None,
|
||||
tap: None,
|
||||
vhost_socket: None,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert_eq!(
|
||||
@@ -3014,10 +3003,6 @@ mod tests {
|
||||
still_valid_config.net = Some(vec![NetConfig {
|
||||
iommu: true,
|
||||
pci_segment: 1,
|
||||
fds: None,
|
||||
id: None,
|
||||
tap: None,
|
||||
vhost_socket: None,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(still_valid_config.validate().is_ok());
|
||||
@@ -3086,10 +3071,6 @@ mod tests {
|
||||
invalid_config.net = Some(vec![NetConfig {
|
||||
iommu: false,
|
||||
pci_segment: 1,
|
||||
fds: None,
|
||||
id: None,
|
||||
tap: None,
|
||||
vhost_socket: None,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert_eq!(
|
||||
@@ -3205,7 +3186,7 @@ mod tests {
|
||||
]);
|
||||
assert!(still_valid_config.validate().is_ok());
|
||||
|
||||
let mut invalid_config = valid_config;
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.devices = Some(vec![
|
||||
DeviceConfig {
|
||||
path: "/device1".into(),
|
||||
@@ -3217,5 +3198,16 @@ mod tests {
|
||||
},
|
||||
]);
|
||||
assert!(invalid_config.validate().is_err());
|
||||
|
||||
let mut still_valid_config = valid_config;
|
||||
// SAFETY: Safe as the file was just opened
|
||||
let fd1 = unsafe { libc::dup(File::open("/dev/null").unwrap().as_raw_fd()) };
|
||||
// SAFETY: Safe as the file was just opened
|
||||
let fd2 = unsafe { libc::dup(File::open("/dev/null").unwrap().as_raw_fd()) };
|
||||
// SAFETY: safe as both FDs are valid
|
||||
unsafe {
|
||||
still_valid_config.add_preserved_fds(vec![fd1, fd2]);
|
||||
}
|
||||
let _still_valid_config = still_valid_config.clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ use hypervisor::arch::x86::MsrEntry;
|
||||
use hypervisor::arch::x86::{SpecialRegisters, StandardRegisters};
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use hypervisor::kvm::kvm_bindings;
|
||||
#[cfg(all(target_arch = "aarch64", feature = "kvm"))]
|
||||
use hypervisor::kvm::kvm_ioctls::Cap;
|
||||
#[cfg(feature = "tdx")]
|
||||
use hypervisor::kvm::{TdxExitDetails, TdxExitStatus};
|
||||
use hypervisor::{CpuState, HypervisorCpuError, HypervisorType, VmExit, VmOps};
|
||||
@@ -370,7 +372,14 @@ impl Vcpu {
|
||||
.map_err(Error::VcpuArmPreferredTarget)?;
|
||||
// We already checked that the capability is supported.
|
||||
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PSCI_0_2;
|
||||
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PMU_V3;
|
||||
if vm
|
||||
.as_any()
|
||||
.downcast_ref::<hypervisor::kvm::KvmVm>()
|
||||
.unwrap()
|
||||
.check_extension(Cap::ArmPmuV3)
|
||||
{
|
||||
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_PMU_V3;
|
||||
}
|
||||
// Non-boot cpus are powered off initially.
|
||||
if self.id > 0 {
|
||||
kvi.features[0] |= 1 << kvm_bindings::KVM_ARM_VCPU_POWER_OFF;
|
||||
|
||||
@@ -70,6 +70,7 @@ use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::path::PathBuf;
|
||||
use std::result;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
use tracer::trace_scoped;
|
||||
@@ -100,6 +101,7 @@ use vm_migration::{
|
||||
use vm_virtio::AccessPlatform;
|
||||
use vm_virtio::VirtioDeviceType;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::terminal::Terminal;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
const MMIO_LEN: u64 = 0x1000;
|
||||
@@ -831,6 +833,9 @@ pub struct DeviceManager {
|
||||
// pty foreground status,
|
||||
console_resize_pipe: Option<Arc<File>>,
|
||||
|
||||
// Are any devices using the tty?
|
||||
on_tty: Option<Arc<AtomicBool>>,
|
||||
|
||||
// Interrupt controller
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
interrupt_controller: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
||||
@@ -1115,6 +1120,7 @@ impl DeviceManager {
|
||||
serial_manager: None,
|
||||
console_pty: None,
|
||||
console_resize_pipe: None,
|
||||
on_tty: None,
|
||||
virtio_mem_devices: Vec::new(),
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
gpio_device: None,
|
||||
@@ -1162,6 +1168,7 @@ impl DeviceManager {
|
||||
serial_pty: Option<PtyPair>,
|
||||
console_pty: Option<PtyPair>,
|
||||
console_resize_pipe: Option<File>,
|
||||
on_tty: Arc<AtomicBool>,
|
||||
) -> DeviceManagerResult<()> {
|
||||
trace_scoped!("create_devices");
|
||||
|
||||
@@ -1223,7 +1230,9 @@ impl DeviceManager {
|
||||
serial_pty,
|
||||
console_pty,
|
||||
console_resize_pipe,
|
||||
&on_tty,
|
||||
)?;
|
||||
self.on_tty = Some(on_tty);
|
||||
|
||||
if let Some(tpm) = self.config.clone().lock().unwrap().tpm.as_ref() {
|
||||
let tpm_dev = self.add_tpm_device(tpm.socket.clone())?;
|
||||
@@ -1864,7 +1873,7 @@ impl DeviceManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_raw_mode(&self, f: &mut File) -> vmm_sys_util::errno::Result<()> {
|
||||
fn set_raw_mode(&self, f: &mut dyn AsRawFd) -> vmm_sys_util::errno::Result<()> {
|
||||
// SAFETY: FFI call. Variable t is guaranteed to be a valid termios from modify_mode.
|
||||
self.modify_mode(f.as_raw_fd(), |t| unsafe { cfmakeraw(t) })
|
||||
}
|
||||
@@ -1888,6 +1897,7 @@ impl DeviceManager {
|
||||
virtio_devices: &mut Vec<MetaVirtioDevice>,
|
||||
console_pty: Option<PtyPair>,
|
||||
resize_pipe: Option<File>,
|
||||
on_tty: &Arc<AtomicBool>,
|
||||
) -> DeviceManagerResult<Option<Arc<virtio_devices::ConsoleResizer>>> {
|
||||
let console_config = self.config.lock().unwrap().console.clone();
|
||||
let endpoint = match console_config.mode {
|
||||
@@ -1926,7 +1936,12 @@ impl DeviceManager {
|
||||
return vmm_sys_util::errno::errno_result().map_err(DeviceManagerError::DupFd);
|
||||
}
|
||||
// SAFETY: stdout is valid and owned solely by us.
|
||||
let stdout = unsafe { File::from_raw_fd(stdout) };
|
||||
let mut stdout = unsafe { File::from_raw_fd(stdout) };
|
||||
|
||||
on_tty.store(true, Ordering::SeqCst);
|
||||
|
||||
// Make sure stdout is in raw mode, if it's a terminal.
|
||||
let _ = self.set_raw_mode(&mut stdout);
|
||||
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
if unsafe { libc::isatty(libc::STDOUT_FILENO) } == 1 {
|
||||
@@ -2004,6 +2019,7 @@ impl DeviceManager {
|
||||
serial_pty: Option<PtyPair>,
|
||||
console_pty: Option<PtyPair>,
|
||||
console_resize_pipe: Option<File>,
|
||||
on_tty: &Arc<AtomicBool>,
|
||||
) -> DeviceManagerResult<Arc<Console>> {
|
||||
let serial_config = self.config.lock().unwrap().serial.clone();
|
||||
let serial_writer: Option<Box<dyn io::Write + Send>> = match serial_config.mode {
|
||||
@@ -2025,7 +2041,12 @@ impl DeviceManager {
|
||||
}
|
||||
None
|
||||
}
|
||||
ConsoleOutputMode::Tty => Some(Box::new(stdout())),
|
||||
ConsoleOutputMode::Tty => {
|
||||
let mut out = stdout();
|
||||
on_tty.store(true, Ordering::SeqCst);
|
||||
let _ = self.set_raw_mode(&mut out);
|
||||
Some(Box::new(out))
|
||||
}
|
||||
ConsoleOutputMode::Off | ConsoleOutputMode::Null => None,
|
||||
};
|
||||
if serial_config.mode != ConsoleOutputMode::Off {
|
||||
@@ -2052,8 +2073,12 @@ impl DeviceManager {
|
||||
};
|
||||
}
|
||||
|
||||
let console_resizer =
|
||||
self.add_virtio_console_device(virtio_devices, console_pty, console_resize_pipe)?;
|
||||
let console_resizer = self.add_virtio_console_device(
|
||||
virtio_devices,
|
||||
console_pty,
|
||||
console_resize_pipe,
|
||||
on_tty,
|
||||
)?;
|
||||
|
||||
Ok(Arc::new(Console { console_resizer }))
|
||||
}
|
||||
@@ -2388,26 +2413,31 @@ impl DeviceManager {
|
||||
.map_err(DeviceManagerError::CreateVirtioNet)?,
|
||||
))
|
||||
} else if let Some(fds) = &net_cfg.fds {
|
||||
Arc::new(Mutex::new(
|
||||
virtio_devices::Net::from_tap_fds(
|
||||
id.clone(),
|
||||
fds,
|
||||
Some(net_cfg.mac),
|
||||
net_cfg.mtu,
|
||||
self.force_iommu | net_cfg.iommu,
|
||||
net_cfg.queue_size,
|
||||
self.seccomp_action.clone(),
|
||||
net_cfg.rate_limiter_config,
|
||||
self.exit_evt
|
||||
.try_clone()
|
||||
.map_err(DeviceManagerError::EventFd)?,
|
||||
state,
|
||||
net_cfg.offload_tso,
|
||||
net_cfg.offload_ufo,
|
||||
net_cfg.offload_csum,
|
||||
)
|
||||
.map_err(DeviceManagerError::CreateVirtioNet)?,
|
||||
))
|
||||
let net = virtio_devices::Net::from_tap_fds(
|
||||
id.clone(),
|
||||
fds,
|
||||
Some(net_cfg.mac),
|
||||
net_cfg.mtu,
|
||||
self.force_iommu | net_cfg.iommu,
|
||||
net_cfg.queue_size,
|
||||
self.seccomp_action.clone(),
|
||||
net_cfg.rate_limiter_config,
|
||||
self.exit_evt
|
||||
.try_clone()
|
||||
.map_err(DeviceManagerError::EventFd)?,
|
||||
state,
|
||||
net_cfg.offload_tso,
|
||||
net_cfg.offload_ufo,
|
||||
net_cfg.offload_csum,
|
||||
)
|
||||
.map_err(DeviceManagerError::CreateVirtioNet)?;
|
||||
|
||||
// SAFETY: 'fds' are valid because TAP devices are created successfully
|
||||
unsafe {
|
||||
self.config.lock().unwrap().add_preserved_fds(fds.clone());
|
||||
}
|
||||
|
||||
Arc::new(Mutex::new(net))
|
||||
} else {
|
||||
Arc::new(Mutex::new(
|
||||
virtio_devices::Net::new(
|
||||
@@ -4631,5 +4661,11 @@ impl Drop for DeviceManager {
|
||||
for handle in self.virtio_devices.drain(..) {
|
||||
handle.virtio_device.lock().unwrap().shutdown();
|
||||
}
|
||||
|
||||
if let Some(ref on_tty) = self.on_tty {
|
||||
if on_tty.load(Ordering::SeqCst) {
|
||||
let _ = std::io::stdin().lock().set_canon_mode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ use std::os::unix::net::UnixListener;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::panic::AssertUnwindSafe;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::{Receiver, RecvError, SendError, Sender};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
@@ -407,12 +408,13 @@ pub struct Vmm {
|
||||
activate_evt: EventFd,
|
||||
signals: Option<Handle>,
|
||||
threads: Vec<thread::JoinHandle<()>>,
|
||||
on_tty: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl Vmm {
|
||||
pub const HANDLED_SIGNALS: [i32; 2] = [SIGTERM, SIGINT];
|
||||
|
||||
fn signal_handler(mut signals: Signals, on_tty: bool, exit_evt: &EventFd) {
|
||||
fn signal_handler(mut signals: Signals, on_tty: Arc<AtomicBool>, exit_evt: &EventFd) {
|
||||
for sig in &Self::HANDLED_SIGNALS {
|
||||
unblock_signal(*sig).unwrap();
|
||||
}
|
||||
@@ -422,7 +424,7 @@ impl Vmm {
|
||||
SIGTERM | SIGINT => {
|
||||
if exit_evt.write(1).is_err() {
|
||||
// Resetting the terminal is usually done as the VMM exits
|
||||
if on_tty {
|
||||
if on_tty.load(Ordering::SeqCst) {
|
||||
io::stdin()
|
||||
.lock()
|
||||
.set_canon_mode()
|
||||
@@ -442,8 +444,7 @@ impl Vmm {
|
||||
Ok(signals) => {
|
||||
self.signals = Some(signals.handle());
|
||||
let exit_evt = self.exit_evt.try_clone().map_err(Error::EventFdClone)?;
|
||||
// SAFETY: trivially safe
|
||||
let on_tty = unsafe { libc::isatty(libc::STDIN_FILENO) } != 0;
|
||||
let on_tty = Arc::clone(&self.on_tty);
|
||||
|
||||
let signal_handler_seccomp_filter = get_seccomp_filter(
|
||||
&self.seccomp_action,
|
||||
@@ -532,6 +533,7 @@ impl Vmm {
|
||||
activate_evt,
|
||||
signals: None,
|
||||
threads: vec![],
|
||||
on_tty: Arc::new(AtomicBool::new(false)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -582,6 +584,7 @@ impl Vmm {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Arc::clone(&self.on_tty),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@@ -680,6 +683,7 @@ impl Vmm {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Arc::clone(&self.on_tty),
|
||||
Some(snapshot),
|
||||
Some(source_url),
|
||||
Some(restore_cfg.prefault),
|
||||
@@ -760,6 +764,7 @@ impl Vmm {
|
||||
serial_pty,
|
||||
console_pty,
|
||||
console_resize_pipe,
|
||||
Arc::clone(&self.on_tty),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@@ -1262,6 +1267,7 @@ impl Vmm {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Arc::clone(&self.on_tty),
|
||||
Some(snapshot),
|
||||
)
|
||||
.map_err(|e| {
|
||||
@@ -2130,6 +2136,7 @@ mod unit_tests {
|
||||
gdb: false,
|
||||
platform: None,
|
||||
tpm: None,
|
||||
preserved_fds: None,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ use std::mem::size_of;
|
||||
use std::num::Wrapping;
|
||||
use std::ops::Deref;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::time::Instant;
|
||||
use std::{result, str, thread};
|
||||
@@ -95,7 +96,6 @@ use vm_migration::{
|
||||
};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::sock_ctrl_msg::ScmSocket;
|
||||
use vmm_sys_util::terminal::Terminal;
|
||||
|
||||
/// Errors associated with VM management
|
||||
#[derive(Debug, Error)]
|
||||
@@ -138,12 +138,6 @@ pub enum Error {
|
||||
#[error("Error from device manager: {0:?}")]
|
||||
DeviceManager(DeviceManagerError),
|
||||
|
||||
#[error("Cannot setup terminal in raw mode: {0}")]
|
||||
SetTerminalRaw(#[source] vmm_sys_util::errno::Error),
|
||||
|
||||
#[error("Cannot setup terminal in canonical mode.: {0}")]
|
||||
SetTerminalCanon(#[source] vmm_sys_util::errno::Error),
|
||||
|
||||
#[error("Cannot spawn a signal handler thread: {0}")]
|
||||
SignalHandlerSpawn(#[source] io::Error),
|
||||
|
||||
@@ -437,7 +431,6 @@ pub struct Vm {
|
||||
threads: Vec<thread::JoinHandle<()>>,
|
||||
device_manager: Arc<Mutex<DeviceManager>>,
|
||||
config: Arc<Mutex<VmConfig>>,
|
||||
on_tty: bool,
|
||||
state: RwLock<VmState>,
|
||||
cpu_manager: Arc<Mutex<cpu::CpuManager>>,
|
||||
memory_manager: Arc<Mutex<MemoryManager>>,
|
||||
@@ -471,6 +464,7 @@ impl Vm {
|
||||
serial_pty: Option<PtyPair>,
|
||||
console_pty: Option<PtyPair>,
|
||||
console_resize_pipe: Option<File>,
|
||||
on_tty: Arc<AtomicBool>,
|
||||
snapshot: Option<Snapshot>,
|
||||
) -> Result<Self> {
|
||||
trace_scoped!("Vm::new_from_memory_manager");
|
||||
@@ -592,12 +586,9 @@ impl Vm {
|
||||
device_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.create_devices(serial_pty, console_pty, console_resize_pipe)
|
||||
.create_devices(serial_pty, console_pty, console_resize_pipe, on_tty)
|
||||
.map_err(Error::DeviceManager)?;
|
||||
|
||||
// SAFETY: trivially safe
|
||||
let on_tty = unsafe { libc::isatty(libc::STDIN_FILENO) } != 0;
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
let kernel = config
|
||||
.lock()
|
||||
@@ -639,7 +630,6 @@ impl Vm {
|
||||
initramfs,
|
||||
device_manager,
|
||||
config,
|
||||
on_tty,
|
||||
threads: Vec::with_capacity(1),
|
||||
state: RwLock::new(vm_state),
|
||||
cpu_manager,
|
||||
@@ -746,6 +736,7 @@ impl Vm {
|
||||
serial_pty: Option<PtyPair>,
|
||||
console_pty: Option<PtyPair>,
|
||||
console_resize_pipe: Option<File>,
|
||||
on_tty: Arc<AtomicBool>,
|
||||
snapshot: Option<Snapshot>,
|
||||
source_url: Option<&str>,
|
||||
prefault: Option<bool>,
|
||||
@@ -815,6 +806,7 @@ impl Vm {
|
||||
serial_pty,
|
||||
console_pty,
|
||||
console_resize_pipe,
|
||||
on_tty,
|
||||
snapshot,
|
||||
)
|
||||
}
|
||||
@@ -1205,15 +1197,6 @@ impl Vm {
|
||||
|
||||
state.valid_transition(new_state)?;
|
||||
|
||||
if self.on_tty {
|
||||
// Don't forget to set the terminal in canonical mode
|
||||
// before to exit.
|
||||
io::stdin()
|
||||
.lock()
|
||||
.set_canon_mode()
|
||||
.map_err(Error::SetTerminalCanon)?;
|
||||
}
|
||||
|
||||
// Wake up the DeviceManager threads so they will get terminated cleanly
|
||||
self.device_manager
|
||||
.lock()
|
||||
@@ -1915,17 +1898,6 @@ impl Vm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_tty(&self) -> Result<()> {
|
||||
if self.on_tty {
|
||||
io::stdin()
|
||||
.lock()
|
||||
.set_raw_mode()
|
||||
.map_err(Error::SetTerminalRaw)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Creates ACPI tables
|
||||
// In case of TDX being used, this is a no-op since the tables will be
|
||||
// created and passed when populating the HOB.
|
||||
@@ -1979,8 +1951,6 @@ impl Vm {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let rsdp_addr = self.create_acpi_tables();
|
||||
|
||||
self.setup_tty()?;
|
||||
|
||||
// Load kernel synchronously or if asynchronous then wait for load to
|
||||
// finish.
|
||||
let entry_point = self.entry_point()?;
|
||||
@@ -2093,8 +2063,6 @@ impl Vm {
|
||||
.start_restored_vcpus()
|
||||
.map_err(Error::CpuManager)?;
|
||||
|
||||
self.setup_tty()?;
|
||||
|
||||
event!("vm", "restored");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ impl Default for MemoryConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub enum VhostMode {
|
||||
#[default]
|
||||
Client,
|
||||
@@ -248,7 +248,7 @@ impl Default for DiskConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct NetConfig {
|
||||
#[serde(default = "default_netconfig_tap")]
|
||||
pub tap: Option<String>,
|
||||
@@ -563,7 +563,7 @@ pub struct TpmConfig {
|
||||
pub socket: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct VmConfig {
|
||||
#[serde(default)]
|
||||
pub cpus: CpusConfig,
|
||||
@@ -596,4 +596,10 @@ pub struct VmConfig {
|
||||
pub gdb: bool,
|
||||
pub platform: Option<PlatformConfig>,
|
||||
pub tpm: Option<TpmConfig>,
|
||||
// Preseved FDs are the ones that share the same life-time as its holding
|
||||
// VmConfig instance, such as FDs for creating TAP devices.
|
||||
// Perserved FDs will stay open as long as the holding VmConfig instance is
|
||||
// valid, and will be closed when the holding VmConfig instance is destroyed.
|
||||
#[serde(skip)]
|
||||
pub preserved_fds: Option<Vec<i32>>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user