vmm: Add tpm parameter

Add an optional --tpm parameter that takes UNIX Domain
Socket from swtpm.

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
This commit is contained in:
Praveen K Paladugu 2022-09-15 04:11:59 +00:00 committed by Rob Bradford
parent d0b253d15f
commit 7122e2989c
5 changed files with 95 additions and 0 deletions

View File

@ -362,6 +362,14 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
.num_args(1)
.value_parser(["true", "false", "log"])
.default_value("true"),
)
.arg(
Arg::new("tpm")
.long("tpm")
.num_args(1)
.help(config::TpmConfig::SYNTAX)
.group("vmm-config"),
);
#[cfg(target_arch = "x86_64")]
@ -713,6 +721,7 @@ mod unit_tests {
#[cfg(feature = "guest_debug")]
gdb: false,
platform: None,
tpm: None,
};
assert_eq!(expected_vm_config, result_vm_config);
@ -1632,4 +1641,26 @@ mod unit_tests {
compare_vm_config_cli_vs_json(cli, openapi, *equal);
});
}
#[test]
fn test_valid_vm_config_tpm_socket() {
vec![(
vec![
"cloud-hypervisor",
"--kernel",
"/path/to/kernel",
"--tpm",
"socket=/path/to/tpm/sock",
],
r#"{
"payload": {"kernel": "/path/to/kernel"},
"tpm": {"socket": "/path/to/tpm/sock"}
}"#,
true,
)]
.iter()
.for_each(|(cli, openapi, equal)| {
compare_vm_config_cli_vs_json(cli, openapi, *equal);
});
}
}

View File

@ -573,6 +573,8 @@ components:
default: false
platform:
$ref: "#/components/schemas/PlatformConfig"
tpm:
$ref: "#/components/schemas/TpmConfig"
description: Virtual machine configuration
CpuAffinity:
@ -958,6 +960,14 @@ components:
id:
type: string
TpmConfig:
required:
- socket
type: object
properties:
socket:
type: string
VdpaConfig:
required:
- path

View File

@ -95,6 +95,10 @@ pub enum Error {
ParseVdpa(OptionParserError),
/// Missing path for vDPA device
ParseVdpaPathMissing,
/// Failed parsing TPM device
ParseTpm(OptionParserError),
/// Missing path for TPM device
ParseTpmPathMissing,
}
#[derive(Debug, PartialEq, Eq, Error)]
@ -331,6 +335,8 @@ impl fmt::Display for Error {
ParsePlatform(o) => write!(f, "Error parsing --platform: {}", o),
ParseVdpa(o) => write!(f, "Error parsing --vdpa: {}", o),
ParseVdpaPathMissing => write!(f, "Error parsing --vdpa: path missing"),
ParseTpm(o) => write!(f, "Error parsing --tpm: {}", o),
ParseTpmPathMissing => write!(f, "Error parsing --tpm: path missing"),
}
}
}
@ -372,6 +378,7 @@ pub struct VmParams<'a> {
#[cfg(feature = "guest_debug")]
pub gdb: bool,
pub platform: Option<&'a str>,
pub tpm: Option<&'a str>,
}
impl<'a> VmParams<'a> {
@ -423,6 +430,7 @@ impl<'a> VmParams<'a> {
let platform = args.get_one::<String>("platform").map(|x| x as &str);
#[cfg(feature = "guest_debug")]
let gdb = args.contains_id("gdb");
let tpm: Option<&str> = args.get_one::<String>("tpm").map(|x| x as &str);
VmParams {
cpus,
memory,
@ -450,6 +458,7 @@ impl<'a> VmParams<'a> {
#[cfg(feature = "guest_debug")]
gdb,
platform,
tpm,
}
}
}
@ -1751,6 +1760,21 @@ impl RestoreConfig {
}
}
impl TpmConfig {
pub const SYNTAX: &'static str = "TPM device \
\"(UNIX Domain Socket from swtpm) socket=</path/to/a/socket>\"";
pub fn parse(tpm: &str) -> Result<Self> {
let mut parser = OptionParser::new();
parser.add("socket");
parser.parse(tpm).map_err(Error::ParseTpm)?;
let socket = parser
.get("socket")
.map(PathBuf::from)
.ok_or(Error::ParseTpmPathMissing)?;
Ok(TpmConfig { socket })
}
}
impl VmConfig {
fn validate_identifier(
id_list: &mut BTreeSet<String>,
@ -2137,6 +2161,14 @@ impl VmConfig {
None
};
let mut tpm: Option<TpmConfig> = None;
if let Some(tc) = vm_params.tpm {
let tpm_conf = TpmConfig::parse(tc)?;
tpm = Some(TpmConfig {
socket: tpm_conf.socket,
});
}
#[cfg(feature = "guest_debug")]
let gdb = vm_params.gdb;
@ -2164,6 +2196,7 @@ impl VmConfig {
#[cfg(feature = "guest_debug")]
gdb,
platform,
tpm,
};
config.validate().map_err(Error::Validation)?;
Ok(config)
@ -2688,6 +2721,19 @@ mod tests {
Ok(())
}
#[test]
fn test_tpm_parsing() -> Result<()> {
// path is required
assert!(TpmConfig::parse("").is_err());
assert_eq!(
TpmConfig::parse("socket=/var/run/tpm.sock")?,
TpmConfig {
socket: PathBuf::from("/var/run/tpm.sock"),
}
);
Ok(())
}
#[test]
fn test_vsock_parsing() -> Result<()> {
// socket and cid is required
@ -2771,6 +2817,7 @@ mod tests {
#[cfg(feature = "guest_debug")]
gdb: false,
platform: None,
tpm: None,
};
assert!(valid_config.validate().is_ok());

View File

@ -2099,6 +2099,7 @@ mod unit_tests {
#[cfg(feature = "guest_debug")]
gdb: false,
platform: None,
tpm: None,
}))
}

View File

@ -555,6 +555,11 @@ pub fn default_console() -> ConsoleConfig {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct TpmConfig {
pub socket: PathBuf,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct VmConfig {
#[serde(default)]
@ -587,4 +592,5 @@ pub struct VmConfig {
#[cfg(feature = "guest_debug")]
pub gdb: bool,
pub platform: Option<PlatformConfig>,
pub tpm: Option<TpmConfig>,
}