From b69f6d4f6cac6534a5f4575d768fa6fa5c401a0e Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Mon, 6 Jul 2020 16:41:45 +0100 Subject: [PATCH] vhost_user_net, vhost_user_block, option_parser: Remove vmm dependency Remove the vmm dependency from vhost_user_block and vhost_user_net where it was existing to use config::OptionParser. By moving the OptionParser to its own crate at the top-level we can remove the very heavy dependency that these vhost-user backends had. Signed-off-by: Rob Bradford --- Cargo.lock | 9 +- Cargo.toml | 1 + option_parser/Cargo.toml | 5 ++ option_parser/src/lib.rs | 172 ++++++++++++++++++++++++++++++++++++ vhost_user_block/Cargo.toml | 2 +- vhost_user_block/src/lib.rs | 2 +- vhost_user_net/Cargo.toml | 2 +- vhost_user_net/src/lib.rs | 3 +- vmm/Cargo.toml | 1 + vmm/src/config.rs | 166 +--------------------------------- vmm/src/lib.rs | 1 + 11 files changed, 192 insertions(+), 172 deletions(-) create mode 100644 option_parser/Cargo.toml create mode 100644 option_parser/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index a412691b7..b54978609 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -676,6 +676,10 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option_parser" +version = "0.1.0" + [[package]] name = "parking_lot" version = "0.10.2" @@ -1433,13 +1437,13 @@ dependencies = [ "epoll", "libc", "log 0.4.8", + "option_parser", "qcow", "vhost", "vhost_user_backend", "virtio-bindings", "virtio-devices", "vm-memory", - "vmm", "vmm-sys-util", ] @@ -1473,12 +1477,12 @@ dependencies = [ "libc", "log 0.4.8", "net_util", + "option_parser", "vhost", "vhost_user_backend", "virtio-bindings", "virtio-devices", "vm-memory", - "vmm", "vmm-sys-util", ] @@ -1591,6 +1595,7 @@ dependencies = [ "log 0.4.8", "micro_http", "net_util", + "option_parser", "pci", "qcow", "seccomp", diff --git a/Cargo.toml b/Cargo.toml index 26e088978..89362dae8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,4 +65,5 @@ members = [ "arch_gen", "net_gen", "vm-allocator", + "option_parser" ] diff --git a/option_parser/Cargo.toml b/option_parser/Cargo.toml new file mode 100644 index 000000000..e771c2dd0 --- /dev/null +++ b/option_parser/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "option_parser" +version = "0.1.0" +authors = ["The Cloud Hypervisor Authors"] +edition = "2018" diff --git a/option_parser/src/lib.rs b/option_parser/src/lib.rs new file mode 100644 index 000000000..17612a579 --- /dev/null +++ b/option_parser/src/lib.rs @@ -0,0 +1,172 @@ +// Copyright © 2020 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use std::collections::HashMap; +use std::fmt; +use std::str::FromStr; + +#[derive(Default)] +pub struct OptionParser { + options: HashMap, +} + +struct OptionParserValue { + value: Option, + requires_value: bool, +} + +#[derive(Debug)] +pub enum OptionParserError { + UnknownOption(String), + InvalidSyntax(String), + Conversion(String, String), +} + +impl fmt::Display for OptionParserError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + OptionParserError::UnknownOption(s) => write!(f, "unknown option: {}", s), + OptionParserError::InvalidSyntax(s) => write!(f, "invalid syntax:{}", s), + OptionParserError::Conversion(field, value) => { + write!(f, "unable to parse {} for {}", value, field) + } + } + } +} +type OptionParserResult = std::result::Result; + +impl OptionParser { + pub fn new() -> Self { + Self { + options: HashMap::new(), + } + } + + pub fn parse(&mut self, input: &str) -> OptionParserResult<()> { + if input.trim().is_empty() { + return Ok(()); + } + + let options_list: Vec<&str> = input.trim().split(',').collect(); + + for option in options_list.iter() { + let parts: Vec<&str> = option.split('=').collect(); + + match self.options.get_mut(parts[0]) { + None => return Err(OptionParserError::UnknownOption(parts[0].to_owned())), + Some(value) => { + if value.requires_value { + if parts.len() != 2 { + return Err(OptionParserError::InvalidSyntax((*option).to_owned())); + } + value.value = Some(parts[1].trim().to_owned()); + } else { + value.value = Some(String::new()); + } + } + } + } + + Ok(()) + } + + pub fn add(&mut self, option: &str) -> &mut Self { + self.options.insert( + option.to_owned(), + OptionParserValue { + value: None, + requires_value: true, + }, + ); + + self + } + + pub fn add_valueless(&mut self, option: &str) -> &mut Self { + self.options.insert( + option.to_owned(), + OptionParserValue { + value: None, + requires_value: false, + }, + ); + + self + } + + pub fn get(&self, option: &str) -> Option { + self.options + .get(option) + .and_then(|v| v.value.clone()) + .and_then(|s| if s.is_empty() { None } else { Some(s) }) + } + + pub fn is_set(&self, option: &str) -> bool { + self.options + .get(option) + .and_then(|v| v.value.as_ref()) + .is_some() + } + + pub fn convert(&self, option: &str) -> OptionParserResult> { + match self.get(option) { + None => Ok(None), + Some(v) => Ok(Some(v.parse().map_err(|_| { + OptionParserError::Conversion(option.to_owned(), v.to_owned()) + })?)), + } + } +} + +pub struct Toggle(pub bool); + +pub enum ToggleParseError { + InvalidValue(String), +} + +impl FromStr for Toggle { + type Err = ToggleParseError; + + fn from_str(s: &str) -> std::result::Result { + match s.to_lowercase().as_str() { + "" => Ok(Toggle(false)), + "on" => Ok(Toggle(true)), + "off" => Ok(Toggle(false)), + "true" => Ok(Toggle(true)), + "false" => Ok(Toggle(false)), + _ => Err(ToggleParseError::InvalidValue(s.to_owned())), + } + } +} + +pub struct ByteSized(pub u64); + +pub enum ByteSizedParseError { + InvalidValue(String), +} + +impl FromStr for ByteSized { + type Err = ByteSizedParseError; + + fn from_str(s: &str) -> std::result::Result { + Ok(ByteSized({ + let s = s.trim(); + let shift = if s.ends_with('K') { + 10 + } else if s.ends_with('M') { + 20 + } else if s.ends_with('G') { + 30 + } else { + 0 + }; + + let s = s.trim_end_matches(|c| c == 'K' || c == 'M' || c == 'G'); + s.parse::() + .map_err(|_| ByteSizedParseError::InvalidValue(s.to_owned()))? + << shift + })) + } +} diff --git a/vhost_user_block/Cargo.toml b/vhost_user_block/Cargo.toml index 9c473ef96..eaf0e34cb 100644 --- a/vhost_user_block/Cargo.toml +++ b/vhost_user_block/Cargo.toml @@ -9,11 +9,11 @@ clap = { version = "2.33.1", features=["wrap_help"] } epoll = ">=4.0.1" libc = "0.2.71" log = "0.4.8" +option_parser = { path = "../option_parser" } qcow = { path = "../qcow" } vhost_user_backend = { path = "../vhost_user_backend" } vhost_rs = { git = "https://github.com/cloud-hypervisor/vhost", branch = "dragonball", package = "vhost", features = ["vhost-user-slave"] } virtio-bindings = "0.1.0" virtio-devices = { path = "../virtio-devices" } vm-memory = "0.2.1" -vmm = { path = "../vmm" } vmm-sys-util = ">=0.3.1" diff --git a/vhost_user_block/src/lib.rs b/vhost_user_block/src/lib.rs index cbca84d67..4b573ec98 100644 --- a/vhost_user_block/src/lib.rs +++ b/vhost_user_block/src/lib.rs @@ -15,6 +15,7 @@ extern crate virtio_devices; use libc::EFD_NONBLOCK; use log::*; +use option_parser::{OptionParser, OptionParserError, Toggle}; use qcow::{self, ImageType, QcowFile}; use std::fs::File; use std::fs::OpenOptions; @@ -40,7 +41,6 @@ use virtio_devices::block::{build_disk_image_id, Request}; use virtio_devices::VirtioBlockConfig; use vm_memory::ByteValued; use vm_memory::{Bytes, GuestMemoryMmap}; -use vmm::config::{OptionParser, OptionParserError, Toggle}; use vmm_sys_util::eventfd::EventFd; const SECTOR_SHIFT: u8 = 9; diff --git a/vhost_user_net/Cargo.toml b/vhost_user_net/Cargo.toml index 61acfced3..7bf31d879 100644 --- a/vhost_user_net/Cargo.toml +++ b/vhost_user_net/Cargo.toml @@ -10,10 +10,10 @@ epoll = ">=4.0.1" libc = "0.2.71" log = "0.4.8" net_util = { path = "../net_util" } +option_parser = { path = "../option_parser" } vhost_user_backend = { path = "../vhost_user_backend" } vhost_rs = { git = "https://github.com/cloud-hypervisor/vhost", branch = "dragonball", package = "vhost", features = ["vhost-user-slave"] } virtio-bindings = "0.1.0" virtio-devices = { path = "../virtio-devices" } vm-memory = "0.2.1" -vmm = { path = "../vmm" } vmm-sys-util = ">=0.3.1" diff --git a/vhost_user_net/src/lib.rs b/vhost_user_net/src/lib.rs index 01cf70934..f58eabd85 100644 --- a/vhost_user_net/src/lib.rs +++ b/vhost_user_net/src/lib.rs @@ -11,11 +11,11 @@ extern crate net_util; extern crate vhost_rs; extern crate vhost_user_backend; extern crate virtio_devices; -extern crate vmm; use libc::{self, EFD_NONBLOCK}; use log::*; use net_util::{MacAddr, Tap}; +use option_parser::{OptionParser, OptionParserError}; use std::fmt; use std::io::{self}; use std::net::Ipv4Addr; @@ -31,7 +31,6 @@ use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; use virtio_devices::net_util::{open_tap, RxVirtio, TxVirtio}; use virtio_devices::{NetCounters, NetQueuePair}; use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap}; -use vmm::config::{OptionParser, OptionParserError}; use vmm_sys_util::eventfd::EventFd; pub type VhostUserResult = std::result::Result; diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index e690788fb..39f7ead44 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -26,6 +26,7 @@ libc = "0.2.71" log = "0.4.8" micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "master" } net_util = { path = "../net_util" } +option_parser = { path = "../option_parser" } pci = {path = "../pci", optional = true} qcow = { path = "../qcow" } seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v0.21.1" } diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 18b98fd01..128c0730a 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -5,7 +5,7 @@ use clap::ArgMatches; use net_util::MacAddr; -use std::collections::HashMap; +use option_parser::{ByteSized, OptionParser, OptionParserError, Toggle}; use std::convert::From; use std::fmt; use std::net::Ipv4Addr; @@ -155,119 +155,6 @@ impl fmt::Display for Error { pub type Result = result::Result; -#[derive(Default)] -pub struct OptionParser { - options: HashMap, -} - -struct OptionParserValue { - value: Option, - requires_value: bool, -} - -#[derive(Debug)] -pub enum OptionParserError { - UnknownOption(String), - InvalidSyntax(String), - Conversion(String, String), -} - -impl fmt::Display for OptionParserError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - OptionParserError::UnknownOption(s) => write!(f, "unknown option: {}", s), - OptionParserError::InvalidSyntax(s) => write!(f, "invalid syntax:{}", s), - OptionParserError::Conversion(field, value) => { - write!(f, "unable to parse {} for {}", value, field) - } - } - } -} -type OptionParserResult = std::result::Result; - -impl OptionParser { - pub fn new() -> Self { - Self { - options: HashMap::new(), - } - } - - pub fn parse(&mut self, input: &str) -> OptionParserResult<()> { - if input.trim().is_empty() { - return Ok(()); - } - - let options_list: Vec<&str> = input.trim().split(',').collect(); - - for option in options_list.iter() { - let parts: Vec<&str> = option.split('=').collect(); - - match self.options.get_mut(parts[0]) { - None => return Err(OptionParserError::UnknownOption(parts[0].to_owned())), - Some(value) => { - if value.requires_value { - if parts.len() != 2 { - return Err(OptionParserError::InvalidSyntax((*option).to_owned())); - } - value.value = Some(parts[1].trim().to_owned()); - } else { - value.value = Some(String::new()); - } - } - } - } - - Ok(()) - } - - pub fn add(&mut self, option: &str) -> &mut Self { - self.options.insert( - option.to_owned(), - OptionParserValue { - value: None, - requires_value: true, - }, - ); - - self - } - - pub fn add_valueless(&mut self, option: &str) -> &mut Self { - self.options.insert( - option.to_owned(), - OptionParserValue { - value: None, - requires_value: false, - }, - ); - - self - } - - pub fn get(&self, option: &str) -> Option { - self.options - .get(option) - .and_then(|v| v.value.clone()) - .and_then(|s| if s.is_empty() { None } else { Some(s) }) - } - - pub fn is_set(&self, option: &str) -> bool { - self.options - .get(option) - .and_then(|v| v.value.as_ref()) - .is_some() - } - - pub fn convert(&self, option: &str) -> OptionParserResult> { - match self.get(option) { - None => Ok(None), - Some(v) => Ok(Some(v.parse().map_err(|_| { - OptionParserError::Conversion(option.to_owned(), v.to_owned()) - })?)), - } - } -} - pub struct VmParams<'a> { pub cpus: &'a str, pub memory: &'a str, @@ -324,27 +211,6 @@ impl<'a> VmParams<'a> { } } -pub struct Toggle(pub bool); - -pub enum ToggleParseError { - InvalidValue(String), -} - -impl FromStr for Toggle { - type Err = ToggleParseError; - - fn from_str(s: &str) -> std::result::Result { - match s.to_lowercase().as_str() { - "" => Ok(Toggle(false)), - "on" => Ok(Toggle(true)), - "off" => Ok(Toggle(false)), - "true" => Ok(Toggle(true)), - "false" => Ok(Toggle(false)), - _ => Err(ToggleParseError::InvalidValue(s.to_owned())), - } - } -} - #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub enum HotplugMethod { Acpi, @@ -374,36 +240,6 @@ impl FromStr for HotplugMethod { } } -struct ByteSized(u64); - -enum ByteSizedParseError { - InvalidValue(String), -} - -impl FromStr for ByteSized { - type Err = ByteSizedParseError; - - fn from_str(s: &str) -> std::result::Result { - Ok(ByteSized({ - let s = s.trim(); - let shift = if s.ends_with('K') { - 10 - } else if s.ends_with('M') { - 20 - } else if s.ends_with('G') { - 30 - } else { - 0 - }; - - let s = s.trim_end_matches(|c| c == 'K' || c == 'M' || c == 'G'); - s.parse::() - .map_err(|_| ByteSizedParseError::InvalidValue(s.to_owned()))? - << shift - })) - } -} - pub enum CpuTopologyParseError { InvalidValue(String), } diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 2eefe5ae8..53e6c1474 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -6,6 +6,7 @@ extern crate anyhow; extern crate arc_swap; extern crate hypervisor; +extern crate option_parser; #[macro_use] extern crate lazy_static; #[macro_use]