mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-02 01:45:21 +00:00
main, vmm: Let the user define distincts memory zones
Introducing a new CLI option --memory-zone letting the user specify custom memory zones. When this option is present, the --memory size must be explicitly set to 0. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
d25ec66bb6
commit
be475ddc22
13
src/main.rs
13
src/main.rs
@ -114,6 +114,18 @@ fn create_app<'a, 'b>(
|
|||||||
.default_value(&default_memory)
|
.default_value(&default_memory)
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("memory-zone")
|
||||||
|
.long("memory-zone")
|
||||||
|
.help(
|
||||||
|
"User defined memory zone parameters \
|
||||||
|
\"size=<guest_memory_region_size>,file=<backing_file>,\
|
||||||
|
mergeable=on|off,shared=on|off,hugepages=on|off\"",
|
||||||
|
)
|
||||||
|
.takes_value(true)
|
||||||
|
.min_values(1)
|
||||||
|
.group("vm-config"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("kernel")
|
Arg::with_name("kernel")
|
||||||
.long("kernel")
|
.long("kernel")
|
||||||
@ -522,6 +534,7 @@ mod unit_tests {
|
|||||||
hugepages: false,
|
hugepages: false,
|
||||||
balloon: false,
|
balloon: false,
|
||||||
balloon_size: 0,
|
balloon_size: 0,
|
||||||
|
zones: None,
|
||||||
},
|
},
|
||||||
kernel: Some(KernelConfig {
|
kernel: Some(KernelConfig {
|
||||||
path: PathBuf::from("/path/to/kernel"),
|
path: PathBuf::from("/path/to/kernel"),
|
||||||
|
@ -448,6 +448,27 @@ components:
|
|||||||
topology:
|
topology:
|
||||||
$ref: '#/components/schemas/CpuTopology'
|
$ref: '#/components/schemas/CpuTopology'
|
||||||
|
|
||||||
|
MemoryZoneConfig:
|
||||||
|
required:
|
||||||
|
- size
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
size:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
default: 512 MB
|
||||||
|
file:
|
||||||
|
type: string
|
||||||
|
mergeable:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
shared:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
hugepages:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
MemoryConfig:
|
MemoryConfig:
|
||||||
required:
|
required:
|
||||||
- size
|
- size
|
||||||
@ -477,6 +498,10 @@ components:
|
|||||||
balloon:
|
balloon:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
zones:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/MemoryZoneConfig'
|
||||||
|
|
||||||
KernelConfig:
|
KernelConfig:
|
||||||
required:
|
required:
|
||||||
|
@ -42,6 +42,8 @@ pub enum Error {
|
|||||||
ParseCpus(OptionParserError),
|
ParseCpus(OptionParserError),
|
||||||
/// Error parsing memory options
|
/// Error parsing memory options
|
||||||
ParseMemory(OptionParserError),
|
ParseMemory(OptionParserError),
|
||||||
|
/// Error parsing memory zone options
|
||||||
|
ParseMemoryZone(OptionParserError),
|
||||||
/// Error parsing disk options
|
/// Error parsing disk options
|
||||||
ParseDisk(OptionParserError),
|
ParseDisk(OptionParserError),
|
||||||
/// Error parsing network options
|
/// Error parsing network options
|
||||||
@ -147,6 +149,7 @@ impl fmt::Display for Error {
|
|||||||
ParseVsockCidMissing => write!(f, "Error parsing --vsock: cid missing"),
|
ParseVsockCidMissing => write!(f, "Error parsing --vsock: cid missing"),
|
||||||
ParseVsockSockMissing => write!(f, "Error parsing --vsock: socket missing"),
|
ParseVsockSockMissing => write!(f, "Error parsing --vsock: socket missing"),
|
||||||
ParseMemory(o) => write!(f, "Error parsing --memory: {}", o),
|
ParseMemory(o) => write!(f, "Error parsing --memory: {}", o),
|
||||||
|
ParseMemoryZone(o) => write!(f, "Error parsing --memory-zone: {}", o),
|
||||||
ParseNetwork(o) => write!(f, "Error parsing --net: {}", o),
|
ParseNetwork(o) => write!(f, "Error parsing --net: {}", o),
|
||||||
ParseDisk(o) => write!(f, "Error parsing --disk: {}", o),
|
ParseDisk(o) => write!(f, "Error parsing --disk: {}", o),
|
||||||
ParseRNG(o) => write!(f, "Error parsing --rng: {}", o),
|
ParseRNG(o) => write!(f, "Error parsing --rng: {}", o),
|
||||||
@ -166,6 +169,7 @@ pub type Result<T> = result::Result<T, Error>;
|
|||||||
pub struct VmParams<'a> {
|
pub struct VmParams<'a> {
|
||||||
pub cpus: &'a str,
|
pub cpus: &'a str,
|
||||||
pub memory: &'a str,
|
pub memory: &'a str,
|
||||||
|
pub memory_zones: Option<Vec<&'a str>>,
|
||||||
pub kernel: Option<&'a str>,
|
pub kernel: Option<&'a str>,
|
||||||
pub initramfs: Option<&'a str>,
|
pub initramfs: Option<&'a str>,
|
||||||
pub cmdline: Option<&'a str>,
|
pub cmdline: Option<&'a str>,
|
||||||
@ -187,6 +191,7 @@ impl<'a> VmParams<'a> {
|
|||||||
// These .unwrap()s cannot fail as there is a default value defined
|
// These .unwrap()s cannot fail as there is a default value defined
|
||||||
let cpus = args.value_of("cpus").unwrap();
|
let cpus = args.value_of("cpus").unwrap();
|
||||||
let memory = args.value_of("memory").unwrap();
|
let memory = args.value_of("memory").unwrap();
|
||||||
|
let memory_zones: Option<Vec<&str>> = args.values_of("memory-zone").map(|x| x.collect());
|
||||||
let rng = args.value_of("rng").unwrap();
|
let rng = args.value_of("rng").unwrap();
|
||||||
let serial = args.value_of("serial").unwrap();
|
let serial = args.value_of("serial").unwrap();
|
||||||
|
|
||||||
@ -207,6 +212,7 @@ impl<'a> VmParams<'a> {
|
|||||||
VmParams {
|
VmParams {
|
||||||
cpus,
|
cpus,
|
||||||
memory,
|
memory,
|
||||||
|
memory_zones,
|
||||||
kernel,
|
kernel,
|
||||||
initramfs,
|
initramfs,
|
||||||
cmdline,
|
cmdline,
|
||||||
@ -337,6 +343,19 @@ impl Default for CpusConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub struct MemoryZoneConfig {
|
||||||
|
pub size: u64,
|
||||||
|
#[serde(default)]
|
||||||
|
pub file: Option<PathBuf>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub mergeable: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub shared: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub hugepages: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct MemoryConfig {
|
pub struct MemoryConfig {
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
@ -356,10 +375,12 @@ pub struct MemoryConfig {
|
|||||||
pub balloon: bool,
|
pub balloon: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub balloon_size: u64,
|
pub balloon_size: u64,
|
||||||
|
#[serde(default)]
|
||||||
|
pub zones: Option<Vec<MemoryZoneConfig>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryConfig {
|
impl MemoryConfig {
|
||||||
pub fn parse(memory: &str) -> Result<Self> {
|
pub fn parse(memory: &str, memory_zones: Option<Vec<&str>>) -> Result<Self> {
|
||||||
let mut parser = OptionParser::new();
|
let mut parser = OptionParser::new();
|
||||||
parser
|
parser
|
||||||
.add("size")
|
.add("size")
|
||||||
@ -407,6 +428,53 @@ impl MemoryConfig {
|
|||||||
.unwrap_or(Toggle(false))
|
.unwrap_or(Toggle(false))
|
||||||
.0;
|
.0;
|
||||||
|
|
||||||
|
let zones: Option<Vec<MemoryZoneConfig>> = if let Some(memory_zones) = &memory_zones {
|
||||||
|
let mut zones = Vec::new();
|
||||||
|
for memory_zone in memory_zones.iter() {
|
||||||
|
let mut parser = OptionParser::new();
|
||||||
|
parser
|
||||||
|
.add("size")
|
||||||
|
.add("file")
|
||||||
|
.add("mergeable")
|
||||||
|
.add("shared")
|
||||||
|
.add("hugepages");
|
||||||
|
parser.parse(memory_zone).map_err(Error::ParseMemoryZone)?;
|
||||||
|
|
||||||
|
let size = parser
|
||||||
|
.convert::<ByteSized>("size")
|
||||||
|
.map_err(Error::ParseMemoryZone)?
|
||||||
|
.unwrap_or(ByteSized(DEFAULT_MEMORY_MB << 20))
|
||||||
|
.0;
|
||||||
|
let file = parser.get("file").map(PathBuf::from);
|
||||||
|
let mergeable = parser
|
||||||
|
.convert::<Toggle>("mergeable")
|
||||||
|
.map_err(Error::ParseMemoryZone)?
|
||||||
|
.unwrap_or(Toggle(false))
|
||||||
|
.0;
|
||||||
|
let shared = parser
|
||||||
|
.convert::<Toggle>("shared")
|
||||||
|
.map_err(Error::ParseMemoryZone)?
|
||||||
|
.unwrap_or(Toggle(false))
|
||||||
|
.0;
|
||||||
|
let hugepages = parser
|
||||||
|
.convert::<Toggle>("hugepages")
|
||||||
|
.map_err(Error::ParseMemoryZone)?
|
||||||
|
.unwrap_or(Toggle(false))
|
||||||
|
.0;
|
||||||
|
|
||||||
|
zones.push(MemoryZoneConfig {
|
||||||
|
size,
|
||||||
|
file,
|
||||||
|
mergeable,
|
||||||
|
shared,
|
||||||
|
hugepages,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Some(zones)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Ok(MemoryConfig {
|
Ok(MemoryConfig {
|
||||||
size,
|
size,
|
||||||
file,
|
file,
|
||||||
@ -417,6 +485,7 @@ impl MemoryConfig {
|
|||||||
hugepages,
|
hugepages,
|
||||||
balloon,
|
balloon,
|
||||||
balloon_size: 0,
|
balloon_size: 0,
|
||||||
|
zones,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -433,6 +502,7 @@ impl Default for MemoryConfig {
|
|||||||
hugepages: false,
|
hugepages: false,
|
||||||
balloon: false,
|
balloon: false,
|
||||||
balloon_size: 0,
|
balloon_size: 0,
|
||||||
|
zones: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1388,7 +1458,7 @@ impl VmConfig {
|
|||||||
|
|
||||||
let config = VmConfig {
|
let config = VmConfig {
|
||||||
cpus: CpusConfig::parse(vm_params.cpus)?,
|
cpus: CpusConfig::parse(vm_params.cpus)?,
|
||||||
memory: MemoryConfig::parse(vm_params.memory)?,
|
memory: MemoryConfig::parse(vm_params.memory, vm_params.memory_zones)?,
|
||||||
kernel,
|
kernel,
|
||||||
initramfs,
|
initramfs,
|
||||||
cmdline: CmdlineConfig::parse(vm_params.cmdline)?,
|
cmdline: CmdlineConfig::parse(vm_params.cmdline)?,
|
||||||
@ -1481,11 +1551,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mem_parsing() -> Result<()> {
|
fn test_mem_parsing() -> Result<()> {
|
||||||
assert_eq!(MemoryConfig::parse("")?, MemoryConfig::default());
|
assert_eq!(MemoryConfig::parse("", None)?, MemoryConfig::default());
|
||||||
// Default string
|
// Default string
|
||||||
assert_eq!(MemoryConfig::parse("size=512M")?, MemoryConfig::default());
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MemoryConfig::parse("size=512M,file=/some/file")?,
|
MemoryConfig::parse("size=512M", None)?,
|
||||||
|
MemoryConfig::default()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
MemoryConfig::parse("size=512M,file=/some/file", None)?,
|
||||||
MemoryConfig {
|
MemoryConfig {
|
||||||
size: 512 << 20,
|
size: 512 << 20,
|
||||||
file: Some(PathBuf::from("/some/file")),
|
file: Some(PathBuf::from("/some/file")),
|
||||||
@ -1493,7 +1566,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MemoryConfig::parse("size=512M,mergeable=on")?,
|
MemoryConfig::parse("size=512M,mergeable=on", None)?,
|
||||||
MemoryConfig {
|
MemoryConfig {
|
||||||
size: 512 << 20,
|
size: 512 << 20,
|
||||||
mergeable: true,
|
mergeable: true,
|
||||||
@ -1501,14 +1574,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MemoryConfig::parse("mergeable=on")?,
|
MemoryConfig::parse("mergeable=on", None)?,
|
||||||
MemoryConfig {
|
MemoryConfig {
|
||||||
mergeable: true,
|
mergeable: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MemoryConfig::parse("size=1G,mergeable=off")?,
|
MemoryConfig::parse("size=1G,mergeable=off", None)?,
|
||||||
MemoryConfig {
|
MemoryConfig {
|
||||||
size: 1 << 30,
|
size: 1 << 30,
|
||||||
mergeable: false,
|
mergeable: false,
|
||||||
@ -1516,20 +1589,20 @@ mod tests {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MemoryConfig::parse("hotplug_method=acpi")?,
|
MemoryConfig::parse("hotplug_method=acpi", None)?,
|
||||||
MemoryConfig {
|
MemoryConfig {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MemoryConfig::parse("hotplug_method=acpi,hotplug_size=512M")?,
|
MemoryConfig::parse("hotplug_method=acpi,hotplug_size=512M", None)?,
|
||||||
MemoryConfig {
|
MemoryConfig {
|
||||||
hotplug_size: Some(512 << 20),
|
hotplug_size: Some(512 << 20),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MemoryConfig::parse("hotplug_method=virtio-mem,hotplug_size=512M")?,
|
MemoryConfig::parse("hotplug_method=virtio-mem,hotplug_size=512M", None)?,
|
||||||
MemoryConfig {
|
MemoryConfig {
|
||||||
hotplug_size: Some(512 << 20),
|
hotplug_size: Some(512 << 20),
|
||||||
hotplug_method: HotplugMethod::VirtioMem,
|
hotplug_method: HotplugMethod::VirtioMem,
|
||||||
@ -1951,6 +2024,7 @@ mod tests {
|
|||||||
hugepages: false,
|
hugepages: false,
|
||||||
balloon: false,
|
balloon: false,
|
||||||
balloon_size: 0,
|
balloon_size: 0,
|
||||||
|
zones: None,
|
||||||
},
|
},
|
||||||
kernel: Some(KernelConfig {
|
kernel: Some(KernelConfig {
|
||||||
path: PathBuf::from("/path/to/kernel"),
|
path: PathBuf::from("/path/to/kernel"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user