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 <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-07-06 16:41:45 +01:00
parent 90261bb9c7
commit b69f6d4f6c
11 changed files with 192 additions and 172 deletions

9
Cargo.lock generated
View File

@ -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",

View File

@ -65,4 +65,5 @@ members = [
"arch_gen",
"net_gen",
"vm-allocator",
"option_parser"
]

5
option_parser/Cargo.toml Normal file
View File

@ -0,0 +1,5 @@
[package]
name = "option_parser"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2018"

172
option_parser/src/lib.rs Normal file
View File

@ -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<String, OptionParserValue>,
}
struct OptionParserValue {
value: Option<String>,
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<T> = std::result::Result<T, OptionParserError>;
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<String> {
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<T: FromStr>(&self, option: &str) -> OptionParserResult<Option<T>> {
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<Self, Self::Err> {
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<Self, Self::Err> {
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::<u64>()
.map_err(|_| ByteSizedParseError::InvalidValue(s.to_owned()))?
<< shift
}))
}
}

View File

@ -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"

View File

@ -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;

View File

@ -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"

View File

@ -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<T> = std::result::Result<T, VhostUserError>;

View File

@ -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" }

View File

@ -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<T> = result::Result<T, Error>;
#[derive(Default)]
pub struct OptionParser {
options: HashMap<String, OptionParserValue>,
}
struct OptionParserValue {
value: Option<String>,
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<T> = std::result::Result<T, OptionParserError>;
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<String> {
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<T: FromStr>(&self, option: &str) -> OptionParserResult<Option<T>> {
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<Self, Self::Err> {
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<Self, Self::Err> {
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::<u64>()
.map_err(|_| ByteSizedParseError::InvalidValue(s.to_owned()))?
<< shift
}))
}
}
pub enum CpuTopologyParseError {
InvalidValue(String),
}

View File

@ -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]