diff --git a/option_parser/src/lib.rs b/option_parser/src/lib.rs index 303e0f814..dac26926f 100644 --- a/option_parser/src/lib.rs +++ b/option_parser/src/lib.rs @@ -214,3 +214,37 @@ impl FromStr for IntegerList { Ok(IntegerList(integer_list)) } } + +pub struct TupleTwoIntegers(pub Vec<(u64, u64)>); + +pub enum TupleTwoIntegersParseError { + InvalidValue(String), +} + +impl FromStr for TupleTwoIntegers { + type Err = TupleTwoIntegersParseError; + + fn from_str(s: &str) -> std::result::Result { + let mut list = Vec::new(); + let tuples_list: Vec<&str> = s.trim().split(':').collect(); + + for tuple in tuples_list.iter() { + let items: Vec<&str> = tuple.split('@').collect(); + + if items.len() != 2 { + return Err(TupleTwoIntegersParseError::InvalidValue(tuple.to_string())); + } + + let item1 = items[0] + .parse::() + .map_err(|_| TupleTwoIntegersParseError::InvalidValue(items[0].to_owned()))?; + let item2 = items[1] + .parse::() + .map_err(|_| TupleTwoIntegersParseError::InvalidValue(items[1].to_owned()))?; + + list.push((item1, item2)); + } + + Ok(TupleTwoIntegers(list)) + } +} diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml index b8c2b5347..59a46c7ac 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml @@ -721,6 +721,19 @@ components: type: boolean default: false + NumaDistance: + required: + - destination + - distance + type: object + properties: + destination: + type: integer + format: uint32 + distance: + type: integer + format: uint8 + NumaConfig: required: - id @@ -734,6 +747,10 @@ components: items: type: integer format: uint8 + distances: + type: array + items: + $ref: '#/components/schemas/NumaDistance' VmResize: type: object diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 21bcbc5d2..e5ef77dac 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -5,7 +5,9 @@ use clap::ArgMatches; use net_util::MacAddr; -use option_parser::{ByteSized, IntegerList, OptionParser, OptionParserError, Toggle}; +use option_parser::{ + ByteSized, IntegerList, OptionParser, OptionParserError, Toggle, TupleTwoIntegers, +}; use std::convert::From; use std::fmt; use std::net::Ipv4Addr; @@ -1210,20 +1212,30 @@ impl SgxEpcConfig { } } +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] +pub struct NumaDistance { + #[serde(default)] + pub destination: u32, + #[serde(default)] + pub distance: u8, +} + #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] pub struct NumaConfig { #[serde(default)] pub id: u32, #[serde(default)] pub cpus: Option>, + #[serde(default)] + pub distances: Option>, } impl NumaConfig { pub const SYNTAX: &'static str = "Settings related to a given NUMA node \ - \"id=,cpus=\""; + \"id=,cpus=,distances=\""; pub fn parse(numa: &str) -> Result { let mut parser = OptionParser::new(); - parser.add("id").add("cpus"); + parser.add("id").add("cpus").add("distances"); parser.parse(numa).map_err(Error::ParseNuma)?; let id = parser @@ -1234,8 +1246,23 @@ impl NumaConfig { .convert::("cpus") .map_err(Error::ParseNuma)? .map(|v| v.0.iter().map(|e| *e as u8).collect()); + let distances = parser + .convert::("distances") + .map_err(Error::ParseNuma)? + .map(|v| { + v.0.iter() + .map(|(e1, e2)| NumaDistance { + destination: *e1 as u32, + distance: *e2 as u8, + }) + .collect() + }); - Ok(NumaConfig { id, cpus }) + Ok(NumaConfig { + id, + cpus, + distances, + }) } }