mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm, main: split ConsoleConfig and SerialConfig into separate structs
This commit introduces a new struct `CommonConsoleConfig` which is the base for the split into `ConsoleConfig` and `SerialConfig`. This is a pre-requisite for allowing more configurable PCI options for the virtio-console device. The commit doesn't change or add any functionality. On-behalf-of: Philipp Schuster@sap.com Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
This commit is contained in:
committed by
Rob Bradford
parent
a56f49787c
commit
04bc6b3ccc
@@ -32,9 +32,10 @@ use vmm::vm_config::FwCfgConfig;
|
|||||||
#[cfg(feature = "ivshmem")]
|
#[cfg(feature = "ivshmem")]
|
||||||
use vmm::vm_config::IvshmemConfig;
|
use vmm::vm_config::IvshmemConfig;
|
||||||
use vmm::vm_config::{
|
use vmm::vm_config::{
|
||||||
BalloonConfig, DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, LandlockConfig,
|
BalloonConfig, ConsoleConfig, DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig,
|
||||||
NetConfig, NumaConfig, PciSegmentConfig, PlatformConfig, PmemConfig, RateLimiterGroupConfig,
|
LandlockConfig, NetConfig, NumaConfig, PciSegmentConfig, PlatformConfig, PmemConfig,
|
||||||
RngConfig, TpmConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig,
|
RateLimiterGroupConfig, RngConfig, SerialConfig, TpmConfig, UserDeviceConfig, VdpaConfig,
|
||||||
|
VmConfig, VsockConfig,
|
||||||
};
|
};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
use vmm_sys_util::signal::block_signal;
|
use vmm_sys_util::signal::block_signal;
|
||||||
@@ -165,7 +166,7 @@ fn get_cli_options_sorted(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
Arg::new("console")
|
Arg::new("console")
|
||||||
.long("console")
|
.long("console")
|
||||||
.help("Control (virtio) console: \"off|null|pty|tty|file=<path>,iommu=on|off\"")
|
.help(ConsoleConfig::SYNTAX)
|
||||||
.default_value("tty")
|
.default_value("tty")
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
Arg::new("cpus")
|
Arg::new("cpus")
|
||||||
@@ -405,7 +406,7 @@ fn get_cli_options_sorted(
|
|||||||
.default_value("true"),
|
.default_value("true"),
|
||||||
Arg::new("serial")
|
Arg::new("serial")
|
||||||
.long("serial")
|
.long("serial")
|
||||||
.help("Control serial port: off|null|pty|tty|file=<path>|socket=<path>")
|
.help(SerialConfig::SYNTAX)
|
||||||
.default_value("null")
|
.default_value("null")
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
Arg::new("tpm")
|
Arg::new("tpm")
|
||||||
@@ -920,8 +921,9 @@ mod unit_tests {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use vmm::vm_config::DebugConsoleConfig;
|
use vmm::vm_config::DebugConsoleConfig;
|
||||||
use vmm::vm_config::{
|
use vmm::vm_config::{
|
||||||
ConsoleConfig, ConsoleOutputMode, CoreScheduling, CpuFeatures, CpusConfig, HotplugMethod,
|
CommonConsoleConfig, ConsoleConfig, ConsoleOutputMode, CoreScheduling, CpuFeatures,
|
||||||
MemoryConfig, PayloadConfig, PciDeviceCommonConfig, RngConfig, VmConfig,
|
CpusConfig, HotplugMethod, MemoryConfig, PayloadConfig, PciDeviceCommonConfig, RngConfig,
|
||||||
|
SerialConfig, VmConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::test_util::assert_args_sorted;
|
use crate::test_util::assert_args_sorted;
|
||||||
@@ -1010,17 +1012,21 @@ mod unit_tests {
|
|||||||
fs: None,
|
fs: None,
|
||||||
generic_vhost_user: None,
|
generic_vhost_user: None,
|
||||||
pmem: None,
|
pmem: None,
|
||||||
serial: ConsoleConfig {
|
serial: SerialConfig {
|
||||||
file: None,
|
common: CommonConsoleConfig {
|
||||||
mode: ConsoleOutputMode::Null,
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Null,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
iommu: false,
|
iommu: false,
|
||||||
socket: None,
|
|
||||||
},
|
},
|
||||||
console: ConsoleConfig {
|
console: ConsoleConfig {
|
||||||
file: None,
|
common: CommonConsoleConfig {
|
||||||
mode: ConsoleOutputMode::Tty,
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Tty,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
iommu: false,
|
iommu: false,
|
||||||
socket: None,
|
|
||||||
},
|
},
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
debug_console: DebugConsoleConfig::default(),
|
debug_console: DebugConsoleConfig::default(),
|
||||||
|
|||||||
@@ -171,17 +171,21 @@ impl RequestHandler for StubApiRequestHandler {
|
|||||||
fs: None,
|
fs: None,
|
||||||
generic_vhost_user: None,
|
generic_vhost_user: None,
|
||||||
pmem: None,
|
pmem: None,
|
||||||
serial: ConsoleConfig {
|
serial: SerialConfig {
|
||||||
file: None,
|
common: CommonConsoleConfig {
|
||||||
mode: ConsoleOutputMode::Null,
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Tty,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
iommu: false,
|
iommu: false,
|
||||||
socket: None,
|
|
||||||
},
|
},
|
||||||
console: ConsoleConfig {
|
console: ConsoleConfig {
|
||||||
file: None,
|
common: CommonConsoleConfig {
|
||||||
mode: ConsoleOutputMode::Tty,
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Tty,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
iommu: false,
|
iommu: false,
|
||||||
socket: None,
|
|
||||||
},
|
},
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
debug_console: DebugConsoleConfig::default(),
|
debug_console: DebugConsoleConfig::default(),
|
||||||
|
|||||||
@@ -128,9 +128,12 @@ pub enum Error {
|
|||||||
/// Error parsing generic vhost-user parameters
|
/// Error parsing generic vhost-user parameters
|
||||||
#[error("Error parsing --generic-vhost-user")]
|
#[error("Error parsing --generic-vhost-user")]
|
||||||
ParseGenericVhostUser(#[source] OptionParserError),
|
ParseGenericVhostUser(#[source] OptionParserError),
|
||||||
/// Failed parsing console
|
/// Failed parsing console parameters
|
||||||
#[error("Error parsing --console")]
|
#[error("Error parsing --console")]
|
||||||
ParseConsole(#[source] OptionParserError),
|
ParseConsole(#[source] OptionParserError),
|
||||||
|
/// Failed parsing serial parameters
|
||||||
|
#[error("Error parsing --serial")]
|
||||||
|
ParseSerial(#[source] OptionParserError),
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
/// Failed parsing debug-console
|
/// Failed parsing debug-console
|
||||||
#[error("Error parsing --debug-console")]
|
#[error("Error parsing --debug-console")]
|
||||||
@@ -2137,17 +2140,18 @@ impl PmemConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConsoleConfig {
|
impl CommonConsoleConfig {
|
||||||
pub fn parse(console: &str) -> Result<Self> {
|
const VALUELESS_OPTIONS: &[&str] = &["off", "pty", "tty", "null"];
|
||||||
|
const VALUE_OPTIONS: &[&str] = &["file", "socket"];
|
||||||
|
|
||||||
|
fn parse(console: &str, map_err: impl Fn(OptionParserError) -> Error) -> Result<Self> {
|
||||||
let mut parser = OptionParser::new();
|
let mut parser = OptionParser::new();
|
||||||
parser
|
parser
|
||||||
.add_all_valueless(&["off", "pty", "tty", "null"])
|
.add_all_valueless(Self::VALUELESS_OPTIONS)
|
||||||
.add("file")
|
.add_all(Self::VALUE_OPTIONS);
|
||||||
.add("iommu")
|
parser.parse_subset(console).map_err(map_err)?;
|
||||||
.add("socket");
|
|
||||||
parser.parse(console).map_err(Error::ParseConsole)?;
|
|
||||||
|
|
||||||
let mut file: Option<PathBuf> = default_consoleconfig_file();
|
let mut file: Option<PathBuf> = None;
|
||||||
let mut socket: Option<PathBuf> = None;
|
let mut socket: Option<PathBuf> = None;
|
||||||
let mut mode: ConsoleOutputMode = ConsoleOutputMode::Off;
|
let mut mode: ConsoleOutputMode = ConsoleOutputMode::Off;
|
||||||
|
|
||||||
@@ -2172,18 +2176,49 @@ impl ConsoleConfig {
|
|||||||
} else {
|
} else {
|
||||||
return Err(Error::ParseConsoleInvalidModeGiven);
|
return Err(Error::ParseConsoleInvalidModeGiven);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(Self { mode, file, socket })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConsoleConfig {
|
||||||
|
pub fn parse(console: &str) -> Result<Self> {
|
||||||
|
let mut parser = OptionParser::new();
|
||||||
|
parser
|
||||||
|
.add_all_valueless(CommonConsoleConfig::VALUELESS_OPTIONS)
|
||||||
|
.add_all(CommonConsoleConfig::VALUE_OPTIONS)
|
||||||
|
.add("iommu");
|
||||||
|
parser.parse(console).map_err(Error::ParseConsole)?;
|
||||||
|
|
||||||
let iommu = parser
|
let iommu = parser
|
||||||
.convert::<Toggle>("iommu")
|
.convert::<Toggle>("iommu")
|
||||||
.map_err(Error::ParseConsole)?
|
.map_err(Error::ParsePciDeviceCommonConfig)?
|
||||||
.unwrap_or(Toggle(false))
|
.unwrap_or(Toggle(false))
|
||||||
.0;
|
.0;
|
||||||
|
|
||||||
Ok(Self {
|
let common = CommonConsoleConfig::parse(console, Error::ParseConsole)?;
|
||||||
file,
|
|
||||||
mode,
|
Ok(Self { common, iommu })
|
||||||
iommu,
|
}
|
||||||
socket,
|
}
|
||||||
})
|
|
||||||
|
impl SerialConfig {
|
||||||
|
pub fn parse(serial: &str) -> Result<Self> {
|
||||||
|
let mut parser = OptionParser::new();
|
||||||
|
parser
|
||||||
|
.add_all_valueless(CommonConsoleConfig::VALUELESS_OPTIONS)
|
||||||
|
.add_all(CommonConsoleConfig::VALUE_OPTIONS)
|
||||||
|
.add("iommu");
|
||||||
|
parser.parse(serial).map_err(Error::ParseSerial)?;
|
||||||
|
|
||||||
|
let iommu = parser
|
||||||
|
.convert::<Toggle>("iommu")
|
||||||
|
.map_err(Error::ParsePciDeviceCommonConfig)?
|
||||||
|
.unwrap_or(Toggle(false))
|
||||||
|
.0;
|
||||||
|
|
||||||
|
let common = CommonConsoleConfig::parse(serial, Error::ParseSerial)?;
|
||||||
|
Ok(Self { common, iommu })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2202,7 +2237,7 @@ impl DebugConsoleConfig {
|
|||||||
.parse(debug_console_ops)
|
.parse(debug_console_ops)
|
||||||
.map_err(Error::ParseConsole)?;
|
.map_err(Error::ParseConsole)?;
|
||||||
|
|
||||||
let mut file: Option<PathBuf> = default_consoleconfig_file();
|
let mut file: Option<PathBuf> = None;
|
||||||
let mut iobase: Option<u16> = None;
|
let mut iobase: Option<u16> = None;
|
||||||
let mut mode: ConsoleOutputMode = ConsoleOutputMode::Off;
|
let mut mode: ConsoleOutputMode = ConsoleOutputMode::Off;
|
||||||
|
|
||||||
@@ -2894,10 +2929,10 @@ impl VmConfig {
|
|||||||
// "console=hvc0 earlyprintk=ttyS0"
|
// "console=hvc0 earlyprintk=ttyS0"
|
||||||
|
|
||||||
let mut tty_consoles = Vec::new();
|
let mut tty_consoles = Vec::new();
|
||||||
if self.console.mode == ConsoleOutputMode::Tty {
|
if self.console.common.mode == ConsoleOutputMode::Tty {
|
||||||
tty_consoles.push("virtio-console");
|
tty_consoles.push("virtio-console");
|
||||||
}
|
}
|
||||||
if self.serial.mode == ConsoleOutputMode::Tty {
|
if self.serial.common.mode == ConsoleOutputMode::Tty {
|
||||||
tty_consoles.push("serial-console");
|
tty_consoles.push("serial-console");
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@@ -2908,11 +2943,12 @@ impl VmConfig {
|
|||||||
warn!("Using TTY output for multiple consoles: {tty_consoles:?}");
|
warn!("Using TTY output for multiple consoles: {tty_consoles:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.console.mode == ConsoleOutputMode::File && self.console.file.is_none() {
|
if self.console.common.mode == ConsoleOutputMode::File && self.console.common.file.is_none()
|
||||||
|
{
|
||||||
return Err(ValidationError::ConsoleFileMissing);
|
return Err(ValidationError::ConsoleFileMissing);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.serial.mode == ConsoleOutputMode::File && self.serial.file.is_none() {
|
if self.serial.common.mode == ConsoleOutputMode::File && self.serial.common.file.is_none() {
|
||||||
return Err(ValidationError::ConsoleFileMissing);
|
return Err(ValidationError::ConsoleFileMissing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3298,7 +3334,7 @@ impl VmConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let console = ConsoleConfig::parse(vm_params.console)?;
|
let console = ConsoleConfig::parse(vm_params.console)?;
|
||||||
let serial = ConsoleConfig::parse(vm_params.serial)?;
|
let serial = SerialConfig::parse(vm_params.serial)?;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
let debug_console = DebugConsoleConfig::parse(vm_params.debug_console)?;
|
let debug_console = DebugConsoleConfig::parse(vm_params.debug_console)?;
|
||||||
|
|
||||||
@@ -4380,79 +4416,59 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_console_parsing() -> Result<()> {
|
fn test_console_parsing() -> Result<()> {
|
||||||
|
let console_config = |mode, file, socket, iommu| ConsoleConfig {
|
||||||
|
common: CommonConsoleConfig { file, mode, socket },
|
||||||
|
iommu,
|
||||||
|
};
|
||||||
|
|
||||||
ConsoleConfig::parse("").unwrap_err();
|
ConsoleConfig::parse("").unwrap_err();
|
||||||
ConsoleConfig::parse("badmode").unwrap_err();
|
ConsoleConfig::parse("badmode").unwrap_err();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ConsoleConfig::parse("off")?,
|
ConsoleConfig::parse("off")?,
|
||||||
ConsoleConfig {
|
console_config(ConsoleOutputMode::Off, None, None, false)
|
||||||
mode: ConsoleOutputMode::Off,
|
|
||||||
iommu: false,
|
|
||||||
file: None,
|
|
||||||
socket: None,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ConsoleConfig::parse("pty")?,
|
ConsoleConfig::parse("pty")?,
|
||||||
ConsoleConfig {
|
console_config(ConsoleOutputMode::Pty, None, None, false)
|
||||||
mode: ConsoleOutputMode::Pty,
|
|
||||||
iommu: false,
|
|
||||||
file: None,
|
|
||||||
socket: None,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ConsoleConfig::parse("tty")?,
|
ConsoleConfig::parse("tty")?,
|
||||||
ConsoleConfig {
|
console_config(ConsoleOutputMode::Tty, None, None, false)
|
||||||
mode: ConsoleOutputMode::Tty,
|
|
||||||
iommu: false,
|
|
||||||
file: None,
|
|
||||||
socket: None,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ConsoleConfig::parse("null")?,
|
ConsoleConfig::parse("null")?,
|
||||||
ConsoleConfig {
|
console_config(ConsoleOutputMode::Null, None, None, false)
|
||||||
mode: ConsoleOutputMode::Null,
|
|
||||||
iommu: false,
|
|
||||||
file: None,
|
|
||||||
socket: None,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ConsoleConfig::parse("file=/tmp/console")?,
|
ConsoleConfig::parse("file=/tmp/console")?,
|
||||||
ConsoleConfig {
|
console_config(
|
||||||
mode: ConsoleOutputMode::File,
|
ConsoleOutputMode::File,
|
||||||
iommu: false,
|
Some(PathBuf::from("/tmp/console")),
|
||||||
file: Some(PathBuf::from("/tmp/console")),
|
None,
|
||||||
socket: None,
|
false
|
||||||
}
|
)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ConsoleConfig::parse("null,iommu=on")?,
|
ConsoleConfig::parse("null,iommu=on")?,
|
||||||
ConsoleConfig {
|
console_config(ConsoleOutputMode::Null, None, None, true)
|
||||||
mode: ConsoleOutputMode::Null,
|
|
||||||
iommu: true,
|
|
||||||
file: None,
|
|
||||||
socket: None,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ConsoleConfig::parse("file=/tmp/console,iommu=on")?,
|
ConsoleConfig::parse("file=/tmp/console,iommu=on")?,
|
||||||
ConsoleConfig {
|
console_config(
|
||||||
mode: ConsoleOutputMode::File,
|
ConsoleOutputMode::File,
|
||||||
iommu: true,
|
Some(PathBuf::from("/tmp/console")),
|
||||||
file: Some(PathBuf::from("/tmp/console")),
|
None,
|
||||||
socket: None,
|
true
|
||||||
}
|
)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ConsoleConfig::parse("socket=/tmp/serial.sock,iommu=on")?,
|
ConsoleConfig::parse("socket=/tmp/serial.sock,iommu=on")?,
|
||||||
ConsoleConfig {
|
console_config(
|
||||||
mode: ConsoleOutputMode::Socket,
|
ConsoleOutputMode::Socket,
|
||||||
iommu: true,
|
None,
|
||||||
file: None,
|
Some(PathBuf::from("/tmp/serial.sock")),
|
||||||
socket: Some(PathBuf::from("/tmp/serial.sock")),
|
true
|
||||||
}
|
)
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -4798,8 +4814,8 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
|||||||
balloon: None,
|
balloon: None,
|
||||||
fs: None,
|
fs: None,
|
||||||
pmem: None,
|
pmem: None,
|
||||||
serial: default_serial(),
|
serial: SerialConfig::default(),
|
||||||
console: default_console(),
|
console: ConsoleConfig::default(),
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
debug_console: DebugConsoleConfig::default(),
|
debug_console: DebugConsoleConfig::default(),
|
||||||
devices: None,
|
devices: None,
|
||||||
@@ -5032,17 +5048,21 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
|||||||
fs: None,
|
fs: None,
|
||||||
generic_vhost_user: None,
|
generic_vhost_user: None,
|
||||||
pmem: None,
|
pmem: None,
|
||||||
serial: ConsoleConfig {
|
serial: SerialConfig {
|
||||||
file: None,
|
common: CommonConsoleConfig {
|
||||||
mode: ConsoleOutputMode::Null,
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Null,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
iommu: false,
|
iommu: false,
|
||||||
socket: None,
|
|
||||||
},
|
},
|
||||||
console: ConsoleConfig {
|
console: ConsoleConfig {
|
||||||
file: None,
|
common: CommonConsoleConfig {
|
||||||
mode: ConsoleOutputMode::Tty,
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Tty,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
iommu: false,
|
iommu: false,
|
||||||
socket: None,
|
|
||||||
},
|
},
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
debug_console: DebugConsoleConfig::default(),
|
debug_console: DebugConsoleConfig::default(),
|
||||||
@@ -5071,8 +5091,8 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
|||||||
valid_config.validate().unwrap();
|
valid_config.validate().unwrap();
|
||||||
|
|
||||||
let mut invalid_config = valid_config.clone();
|
let mut invalid_config = valid_config.clone();
|
||||||
invalid_config.serial.mode = ConsoleOutputMode::Tty;
|
invalid_config.serial.common.mode = ConsoleOutputMode::Tty;
|
||||||
invalid_config.console.mode = ConsoleOutputMode::Tty;
|
invalid_config.console.common.mode = ConsoleOutputMode::Tty;
|
||||||
valid_config.validate().unwrap();
|
valid_config.validate().unwrap();
|
||||||
|
|
||||||
let mut invalid_config = valid_config.clone();
|
let mut invalid_config = valid_config.clone();
|
||||||
@@ -5112,8 +5132,8 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut invalid_config = valid_config.clone();
|
let mut invalid_config = valid_config.clone();
|
||||||
invalid_config.serial.mode = ConsoleOutputMode::File;
|
invalid_config.serial.common.mode = ConsoleOutputMode::File;
|
||||||
invalid_config.serial.file = None;
|
invalid_config.serial.common.file = None;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
invalid_config.validate(),
|
invalid_config.validate(),
|
||||||
Err(ValidationError::ConsoleFileMissing)
|
Err(ValidationError::ConsoleFileMissing)
|
||||||
|
|||||||
@@ -181,9 +181,9 @@ pub(crate) fn pre_create_console_devices(vmm: &mut Vmm) -> ConsoleDeviceResult<C
|
|||||||
let mut original_termios_opt = vmm.original_termios_opt.lock().unwrap();
|
let mut original_termios_opt = vmm.original_termios_opt.lock().unwrap();
|
||||||
|
|
||||||
let console_info = ConsoleInfo {
|
let console_info = ConsoleInfo {
|
||||||
console: match vmconfig.console.mode {
|
console: match vmconfig.console.common.mode {
|
||||||
ConsoleOutputMode::File => {
|
ConsoleOutputMode::File => {
|
||||||
let file = File::create(vmconfig.console.file.as_ref().unwrap())
|
let file = File::create(vmconfig.console.common.file.as_ref().unwrap())
|
||||||
.map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
.map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
||||||
ConsoleTransport::File(Arc::new(file))
|
ConsoleTransport::File(Arc::new(file))
|
||||||
}
|
}
|
||||||
@@ -191,7 +191,7 @@ pub(crate) fn pre_create_console_devices(vmm: &mut Vmm) -> ConsoleDeviceResult<C
|
|||||||
let (main_fd, sub_fd, path) =
|
let (main_fd, sub_fd, path) =
|
||||||
create_pty().map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
create_pty().map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
||||||
set_raw_mode(&sub_fd.as_raw_fd(), &mut original_termios_opt)?;
|
set_raw_mode(&sub_fd.as_raw_fd(), &mut original_termios_opt)?;
|
||||||
vmconfig.console.file = Some(path.clone());
|
vmconfig.console.common.file = Some(path.clone());
|
||||||
vmm.console_resize_pipe = Some(Arc::new(
|
vmm.console_resize_pipe = Some(Arc::new(
|
||||||
listen_for_sigwinch_on_tty(
|
listen_for_sigwinch_on_tty(
|
||||||
sub_fd,
|
sub_fd,
|
||||||
@@ -230,9 +230,9 @@ pub(crate) fn pre_create_console_devices(vmm: &mut Vmm) -> ConsoleDeviceResult<C
|
|||||||
ConsoleOutputMode::Null => ConsoleTransport::Null,
|
ConsoleOutputMode::Null => ConsoleTransport::Null,
|
||||||
ConsoleOutputMode::Off => ConsoleTransport::Off,
|
ConsoleOutputMode::Off => ConsoleTransport::Off,
|
||||||
},
|
},
|
||||||
serial: match vmconfig.serial.mode {
|
serial: match vmconfig.serial.common.mode {
|
||||||
ConsoleOutputMode::File => {
|
ConsoleOutputMode::File => {
|
||||||
let file = File::create(vmconfig.serial.file.as_ref().unwrap())
|
let file = File::create(vmconfig.serial.common.file.as_ref().unwrap())
|
||||||
.map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
.map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
||||||
ConsoleTransport::File(Arc::new(file))
|
ConsoleTransport::File(Arc::new(file))
|
||||||
}
|
}
|
||||||
@@ -240,7 +240,7 @@ pub(crate) fn pre_create_console_devices(vmm: &mut Vmm) -> ConsoleDeviceResult<C
|
|||||||
let (main_fd, sub_fd, path) =
|
let (main_fd, sub_fd, path) =
|
||||||
create_pty().map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
create_pty().map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
||||||
set_raw_mode(&sub_fd.as_raw_fd(), &mut original_termios_opt)?;
|
set_raw_mode(&sub_fd.as_raw_fd(), &mut original_termios_opt)?;
|
||||||
vmconfig.serial.file = Some(path.clone());
|
vmconfig.serial.common.file = Some(path.clone());
|
||||||
ConsoleTransport::Pty(Arc::new(main_fd))
|
ConsoleTransport::Pty(Arc::new(main_fd))
|
||||||
}
|
}
|
||||||
ConsoleOutputMode::Tty => {
|
ConsoleOutputMode::Tty => {
|
||||||
@@ -260,7 +260,7 @@ pub(crate) fn pre_create_console_devices(vmm: &mut Vmm) -> ConsoleDeviceResult<C
|
|||||||
ConsoleTransport::Tty(Arc::new(stdout))
|
ConsoleTransport::Tty(Arc::new(stdout))
|
||||||
}
|
}
|
||||||
ConsoleOutputMode::Socket => {
|
ConsoleOutputMode::Socket => {
|
||||||
let listener = UnixListener::bind(vmconfig.serial.socket.as_ref().unwrap())
|
let listener = UnixListener::bind(vmconfig.serial.common.socket.as_ref().unwrap())
|
||||||
.map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
.map_err(ConsoleDeviceError::CreateConsoleDevice)?;
|
||||||
ConsoleTransport::Socket(Arc::new(listener))
|
ConsoleTransport::Socket(Arc::new(listener))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2440,11 +2440,13 @@ impl DeviceManager {
|
|||||||
.insert(id.clone(), device_node!(id, virtio_console_device));
|
.insert(id.clone(), device_node!(id, virtio_console_device));
|
||||||
|
|
||||||
// Only provide a resizer (for SIGWINCH handling) if the console is attached to the TTY
|
// Only provide a resizer (for SIGWINCH handling) if the console is attached to the TTY
|
||||||
Ok(if matches!(console_config.mode, ConsoleOutputMode::Tty) {
|
Ok(
|
||||||
Some(console_resizer)
|
if matches!(console_config.common.mode, ConsoleOutputMode::Tty) {
|
||||||
} else {
|
Some(console_resizer)
|
||||||
None
|
} else {
|
||||||
})
|
None
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds all devices that behave like a console with respect to the VM
|
/// Adds all devices that behave like a console with respect to the VM
|
||||||
@@ -2482,9 +2484,12 @@ impl DeviceManager {
|
|||||||
ConsoleTransport::Pty(_)
|
ConsoleTransport::Pty(_)
|
||||||
| ConsoleTransport::Tty(_)
|
| ConsoleTransport::Tty(_)
|
||||||
| ConsoleTransport::Socket(_) => {
|
| ConsoleTransport::Socket(_) => {
|
||||||
let serial_manager =
|
let serial_manager = SerialManager::new(
|
||||||
SerialManager::new(serial, console_info.serial, serial_config.socket)
|
serial,
|
||||||
.map_err(DeviceManagerError::CreateSerialManager)?;
|
console_info.serial,
|
||||||
|
serial_config.common.socket,
|
||||||
|
)
|
||||||
|
.map_err(DeviceManagerError::CreateSerialManager)?;
|
||||||
if let Some(mut serial_manager) = serial_manager {
|
if let Some(mut serial_manager) = serial_manager {
|
||||||
serial_manager
|
serial_manager
|
||||||
.start_thread(
|
.start_thread(
|
||||||
@@ -5442,18 +5447,18 @@ impl Aml for DeviceManager {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
let serial_irq = 4;
|
let serial_irq = 4;
|
||||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||||
let serial_irq =
|
let serial_irq = if self.config.lock().unwrap().serial.common.mode == ConsoleOutputMode::Off
|
||||||
if self.config.lock().unwrap().serial.clone().mode == ConsoleOutputMode::Off {
|
{
|
||||||
// If serial is turned off, add a fake device with invalid irq.
|
// If serial is turned off, add a fake device with invalid irq.
|
||||||
31
|
31
|
||||||
} else {
|
} else {
|
||||||
self.get_device_info()
|
self.get_device_info()
|
||||||
.clone()
|
.clone()
|
||||||
.get(&(DeviceType::Serial, DeviceType::Serial.to_string()))
|
.get(&(DeviceType::Serial, DeviceType::Serial.to_string()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.irq()
|
.irq()
|
||||||
};
|
};
|
||||||
if self.config.lock().unwrap().serial.mode != ConsoleOutputMode::Off {
|
if self.config.lock().unwrap().serial.common.mode != ConsoleOutputMode::Off {
|
||||||
aml::Device::new(
|
aml::Device::new(
|
||||||
"_SB_.COM1".into(),
|
"_SB_.COM1".into(),
|
||||||
vec![
|
vec![
|
||||||
|
|||||||
@@ -2653,8 +2653,9 @@ mod unit_tests {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::vm_config::DebugConsoleConfig;
|
use crate::vm_config::DebugConsoleConfig;
|
||||||
use crate::vm_config::{
|
use crate::vm_config::{
|
||||||
ConsoleConfig, ConsoleOutputMode, CoreScheduling, CpuFeatures, CpusConfig, HotplugMethod,
|
CommonConsoleConfig, ConsoleConfig, ConsoleOutputMode, CoreScheduling, CpuFeatures,
|
||||||
MemoryConfig, PayloadConfig, PciDeviceCommonConfig, RngConfig,
|
CpusConfig, HotplugMethod, MemoryConfig, PayloadConfig, PciDeviceCommonConfig, RngConfig,
|
||||||
|
SerialConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn create_dummy_vmm() -> Vmm {
|
fn create_dummy_vmm() -> Vmm {
|
||||||
@@ -2722,18 +2723,22 @@ mod unit_tests {
|
|||||||
fs: None,
|
fs: None,
|
||||||
generic_vhost_user: None,
|
generic_vhost_user: None,
|
||||||
pmem: None,
|
pmem: None,
|
||||||
serial: ConsoleConfig {
|
serial: SerialConfig {
|
||||||
file: None,
|
common: CommonConsoleConfig {
|
||||||
mode: ConsoleOutputMode::Null,
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Null,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
iommu: false,
|
iommu: false,
|
||||||
socket: None,
|
|
||||||
},
|
},
|
||||||
console: ConsoleConfig {
|
console: ConsoleConfig {
|
||||||
file: None,
|
common: CommonConsoleConfig {
|
||||||
// Caution: Don't use `Tty` to not mess with users terminal
|
file: None,
|
||||||
mode: ConsoleOutputMode::Off,
|
// Caution: Don't use `Tty` to not mess with users terminal
|
||||||
|
mode: ConsoleOutputMode::Off,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
iommu: false,
|
iommu: false,
|
||||||
socket: None,
|
|
||||||
},
|
},
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
debug_console: DebugConsoleConfig::default(),
|
debug_console: DebugConsoleConfig::default(),
|
||||||
|
|||||||
@@ -545,21 +545,19 @@ pub enum ConsoleOutputMode {
|
|||||||
Null,
|
Null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Common configuration for plain console configs.
|
||||||
|
///
|
||||||
|
/// Independent of PCI or legacy devices.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct ConsoleConfig {
|
pub struct CommonConsoleConfig {
|
||||||
#[serde(default = "default_consoleconfig_file")]
|
#[serde(default)]
|
||||||
pub file: Option<PathBuf>,
|
pub file: Option<PathBuf>,
|
||||||
pub mode: ConsoleOutputMode,
|
pub mode: ConsoleOutputMode,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub iommu: bool,
|
|
||||||
pub socket: Option<PathBuf>,
|
pub socket: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_consoleconfig_file() -> Option<PathBuf> {
|
impl ApplyLandlock for CommonConsoleConfig {
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ApplyLandlock for ConsoleConfig {
|
|
||||||
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
if self.mode == ConsoleOutputMode::Pty {
|
if self.mode == ConsoleOutputMode::Pty {
|
||||||
landlock.add_rule_with_access(Path::new("/dev/pts"), "rw")?;
|
landlock.add_rule_with_access(Path::new("/dev/pts"), "rw")?;
|
||||||
@@ -575,6 +573,76 @@ impl ApplyLandlock for ConsoleConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configuration for a legacy serial console device.
|
||||||
|
///
|
||||||
|
/// - On x86_64, this is a port I/O-mapped UART16550-compatible device
|
||||||
|
/// - On aarch64, this is a MMIO-mapped PL011 device
|
||||||
|
/// - On RISCV, this is a MMIO-mapped UART16550-compatible device
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
|
pub struct SerialConfig {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub common: CommonConsoleConfig,
|
||||||
|
#[serde(default, skip_serializing_if = "<&bool as std::ops::Not>::not")]
|
||||||
|
pub iommu: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialConfig {
|
||||||
|
pub const SYNTAX: &str =
|
||||||
|
"Control serial port: \"off|null|pty|tty|file=<path>|socket=<path>,iommu=on|off\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SerialConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
common: CommonConsoleConfig {
|
||||||
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Null,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
|
iommu: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for SerialConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
self.common.apply_landlock(landlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration for a virtio-console device.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
|
pub struct ConsoleConfig {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub common: CommonConsoleConfig,
|
||||||
|
#[serde(default, skip_serializing_if = "<&bool as std::ops::Not>::not")]
|
||||||
|
pub iommu: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConsoleConfig {
|
||||||
|
pub const SYNTAX: &str =
|
||||||
|
"Control (virtio) console: \"off|null|pty|tty|file=<path>,iommu=on|off\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ConsoleConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
common: CommonConsoleConfig {
|
||||||
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Tty,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
|
iommu: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplyLandlock for ConsoleConfig {
|
||||||
|
fn apply_landlock(&self, landlock: &mut Landlock) -> LandlockResult<()> {
|
||||||
|
self.common.apply_landlock(landlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct DebugConsoleConfig {
|
pub struct DebugConsoleConfig {
|
||||||
@@ -929,24 +997,6 @@ impl ApplyLandlock for PayloadConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_serial() -> ConsoleConfig {
|
|
||||||
ConsoleConfig {
|
|
||||||
file: None,
|
|
||||||
mode: ConsoleOutputMode::Null,
|
|
||||||
iommu: false,
|
|
||||||
socket: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_console() -> ConsoleConfig {
|
|
||||||
ConsoleConfig {
|
|
||||||
file: None,
|
|
||||||
mode: ConsoleOutputMode::Tty,
|
|
||||||
iommu: false,
|
|
||||||
socket: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct TpmConfig {
|
pub struct TpmConfig {
|
||||||
pub socket: PathBuf,
|
pub socket: PathBuf,
|
||||||
@@ -988,9 +1038,9 @@ pub struct VmConfig {
|
|||||||
pub generic_vhost_user: Option<Vec<GenericVhostUserConfig>>,
|
pub generic_vhost_user: Option<Vec<GenericVhostUserConfig>>,
|
||||||
pub fs: Option<Vec<FsConfig>>,
|
pub fs: Option<Vec<FsConfig>>,
|
||||||
pub pmem: Option<Vec<PmemConfig>>,
|
pub pmem: Option<Vec<PmemConfig>>,
|
||||||
#[serde(default = "default_serial")]
|
#[serde(default)]
|
||||||
pub serial: ConsoleConfig,
|
pub serial: SerialConfig,
|
||||||
#[serde(default = "default_console")]
|
#[serde(default)]
|
||||||
pub console: ConsoleConfig,
|
pub console: ConsoleConfig,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|||||||
Reference in New Issue
Block a user