mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-03 11:25:20 +00:00
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:
parent
90261bb9c7
commit
b69f6d4f6c
9
Cargo.lock
generated
9
Cargo.lock
generated
@ -676,6 +676,10 @@ dependencies = [
|
|||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "option_parser"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@ -1433,13 +1437,13 @@ dependencies = [
|
|||||||
"epoll",
|
"epoll",
|
||||||
"libc",
|
"libc",
|
||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
|
"option_parser",
|
||||||
"qcow",
|
"qcow",
|
||||||
"vhost",
|
"vhost",
|
||||||
"vhost_user_backend",
|
"vhost_user_backend",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"virtio-devices",
|
"virtio-devices",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vmm",
|
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1473,12 +1477,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
"net_util",
|
"net_util",
|
||||||
|
"option_parser",
|
||||||
"vhost",
|
"vhost",
|
||||||
"vhost_user_backend",
|
"vhost_user_backend",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"virtio-devices",
|
"virtio-devices",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vmm",
|
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1591,6 +1595,7 @@ dependencies = [
|
|||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
"micro_http",
|
"micro_http",
|
||||||
"net_util",
|
"net_util",
|
||||||
|
"option_parser",
|
||||||
"pci",
|
"pci",
|
||||||
"qcow",
|
"qcow",
|
||||||
"seccomp",
|
"seccomp",
|
||||||
|
@ -65,4 +65,5 @@ members = [
|
|||||||
"arch_gen",
|
"arch_gen",
|
||||||
"net_gen",
|
"net_gen",
|
||||||
"vm-allocator",
|
"vm-allocator",
|
||||||
|
"option_parser"
|
||||||
]
|
]
|
||||||
|
5
option_parser/Cargo.toml
Normal file
5
option_parser/Cargo.toml
Normal 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
172
option_parser/src/lib.rs
Normal 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
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
@ -9,11 +9,11 @@ clap = { version = "2.33.1", features=["wrap_help"] }
|
|||||||
epoll = ">=4.0.1"
|
epoll = ">=4.0.1"
|
||||||
libc = "0.2.71"
|
libc = "0.2.71"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
|
option_parser = { path = "../option_parser" }
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
vhost_user_backend = { path = "../vhost_user_backend" }
|
vhost_user_backend = { path = "../vhost_user_backend" }
|
||||||
vhost_rs = { git = "https://github.com/cloud-hypervisor/vhost", branch = "dragonball", package = "vhost", features = ["vhost-user-slave"] }
|
vhost_rs = { git = "https://github.com/cloud-hypervisor/vhost", branch = "dragonball", package = "vhost", features = ["vhost-user-slave"] }
|
||||||
virtio-bindings = "0.1.0"
|
virtio-bindings = "0.1.0"
|
||||||
virtio-devices = { path = "../virtio-devices" }
|
virtio-devices = { path = "../virtio-devices" }
|
||||||
vm-memory = "0.2.1"
|
vm-memory = "0.2.1"
|
||||||
vmm = { path = "../vmm" }
|
|
||||||
vmm-sys-util = ">=0.3.1"
|
vmm-sys-util = ">=0.3.1"
|
||||||
|
@ -15,6 +15,7 @@ extern crate virtio_devices;
|
|||||||
|
|
||||||
use libc::EFD_NONBLOCK;
|
use libc::EFD_NONBLOCK;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use option_parser::{OptionParser, OptionParserError, Toggle};
|
||||||
use qcow::{self, ImageType, QcowFile};
|
use qcow::{self, ImageType, QcowFile};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
@ -40,7 +41,6 @@ use virtio_devices::block::{build_disk_image_id, Request};
|
|||||||
use virtio_devices::VirtioBlockConfig;
|
use virtio_devices::VirtioBlockConfig;
|
||||||
use vm_memory::ByteValued;
|
use vm_memory::ByteValued;
|
||||||
use vm_memory::{Bytes, GuestMemoryMmap};
|
use vm_memory::{Bytes, GuestMemoryMmap};
|
||||||
use vmm::config::{OptionParser, OptionParserError, Toggle};
|
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
const SECTOR_SHIFT: u8 = 9;
|
const SECTOR_SHIFT: u8 = 9;
|
||||||
|
@ -10,10 +10,10 @@ epoll = ">=4.0.1"
|
|||||||
libc = "0.2.71"
|
libc = "0.2.71"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
net_util = { path = "../net_util" }
|
net_util = { path = "../net_util" }
|
||||||
|
option_parser = { path = "../option_parser" }
|
||||||
vhost_user_backend = { path = "../vhost_user_backend" }
|
vhost_user_backend = { path = "../vhost_user_backend" }
|
||||||
vhost_rs = { git = "https://github.com/cloud-hypervisor/vhost", branch = "dragonball", package = "vhost", features = ["vhost-user-slave"] }
|
vhost_rs = { git = "https://github.com/cloud-hypervisor/vhost", branch = "dragonball", package = "vhost", features = ["vhost-user-slave"] }
|
||||||
virtio-bindings = "0.1.0"
|
virtio-bindings = "0.1.0"
|
||||||
virtio-devices = { path = "../virtio-devices" }
|
virtio-devices = { path = "../virtio-devices" }
|
||||||
vm-memory = "0.2.1"
|
vm-memory = "0.2.1"
|
||||||
vmm = { path = "../vmm" }
|
|
||||||
vmm-sys-util = ">=0.3.1"
|
vmm-sys-util = ">=0.3.1"
|
||||||
|
@ -11,11 +11,11 @@ extern crate net_util;
|
|||||||
extern crate vhost_rs;
|
extern crate vhost_rs;
|
||||||
extern crate vhost_user_backend;
|
extern crate vhost_user_backend;
|
||||||
extern crate virtio_devices;
|
extern crate virtio_devices;
|
||||||
extern crate vmm;
|
|
||||||
|
|
||||||
use libc::{self, EFD_NONBLOCK};
|
use libc::{self, EFD_NONBLOCK};
|
||||||
use log::*;
|
use log::*;
|
||||||
use net_util::{MacAddr, Tap};
|
use net_util::{MacAddr, Tap};
|
||||||
|
use option_parser::{OptionParser, OptionParserError};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{self};
|
use std::io::{self};
|
||||||
use std::net::Ipv4Addr;
|
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::net_util::{open_tap, RxVirtio, TxVirtio};
|
||||||
use virtio_devices::{NetCounters, NetQueuePair};
|
use virtio_devices::{NetCounters, NetQueuePair};
|
||||||
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
|
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
|
||||||
use vmm::config::{OptionParser, OptionParserError};
|
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
pub type VhostUserResult<T> = std::result::Result<T, VhostUserError>;
|
pub type VhostUserResult<T> = std::result::Result<T, VhostUserError>;
|
||||||
|
@ -26,6 +26,7 @@ libc = "0.2.71"
|
|||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "master" }
|
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "master" }
|
||||||
net_util = { path = "../net_util" }
|
net_util = { path = "../net_util" }
|
||||||
|
option_parser = { path = "../option_parser" }
|
||||||
pci = {path = "../pci", optional = true}
|
pci = {path = "../pci", optional = true}
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v0.21.1" }
|
seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v0.21.1" }
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use net_util::MacAddr;
|
use net_util::MacAddr;
|
||||||
use std::collections::HashMap;
|
use option_parser::{ByteSized, OptionParser, OptionParserError, Toggle};
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
@ -155,119 +155,6 @@ impl fmt::Display for Error {
|
|||||||
|
|
||||||
pub type Result<T> = result::Result<T, 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 struct VmParams<'a> {
|
||||||
pub cpus: &'a str,
|
pub cpus: &'a str,
|
||||||
pub memory: &'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)]
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
pub enum HotplugMethod {
|
pub enum HotplugMethod {
|
||||||
Acpi,
|
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 {
|
pub enum CpuTopologyParseError {
|
||||||
InvalidValue(String),
|
InvalidValue(String),
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
extern crate anyhow;
|
extern crate anyhow;
|
||||||
extern crate arc_swap;
|
extern crate arc_swap;
|
||||||
extern crate hypervisor;
|
extern crate hypervisor;
|
||||||
|
extern crate option_parser;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
Loading…
Reference in New Issue
Block a user