diff options
author | Alyssa Ross <hi@alyssa.is> | 2020-04-10 13:44:58 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2020-04-10 13:45:14 +0000 |
commit | 8404e234c3428a682dfd5ee900936a8032243ba7 (patch) | |
tree | 458d0c9db4e145c1ace3ea7e50c3a50a45f020c3 /src | |
parent | d1ea7fc8d6b750ba75df719fb932984ab1ef5f11 (diff) | |
parent | 4ee9bffbd5722ac6602abaac6f691917add12f48 (diff) | |
download | crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.gz crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.bz2 crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.lz crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.xz crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.zst crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.zip |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'src')
-rw-r--r-- | src/crosvm.rs | 2 | ||||
-rw-r--r-- | src/linux.rs | 345 | ||||
-rw-r--r-- | src/main.rs | 28 | ||||
-rw-r--r-- | src/plugin/mod.rs | 2 | ||||
-rw-r--r-- | src/plugin/process.rs | 2 |
5 files changed, 210 insertions, 169 deletions
diff --git a/src/crosvm.rs b/src/crosvm.rs index 81344c3..a55d2e4 100644 --- a/src/crosvm.rs +++ b/src/crosvm.rs @@ -176,6 +176,7 @@ pub struct Config { pub host_ip: Option<net::Ipv4Addr>, pub netmask: Option<net::Ipv4Addr>, pub mac_address: Option<net_util::MacAddress>, + pub net_vq_pairs: Option<u16>, pub vhost_net: bool, pub tap_fd: Vec<RawFd>, pub cid: Option<u64>, @@ -223,6 +224,7 @@ impl Default for Config { host_ip: None, netmask: None, mac_address: None, + net_vq_pairs: None, vhost_net: false, tap_fd: Vec::new(), cid: None, diff --git a/src/linux.rs b/src/linux.rs index 130644d..9dbdb5c 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -3,7 +3,7 @@ // found in the LICENSE file. use std; -use std::cmp::min; +use std::cmp::max; use std::convert::TryFrom; use std::error::Error as StdError; use std::ffi::CStr; @@ -23,7 +23,7 @@ use std::str; use std::sync::{Arc, Barrier}; use std::thread; use std::thread::JoinHandle; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::time::Duration; use libc::{self, c_int, gid_t, uid_t}; @@ -38,7 +38,6 @@ use io_jail::{self, Minijail}; use kvm::*; use msg_socket::{MsgError, MsgReceiver, MsgSender, MsgSocket}; use net_util::{Error as NetError, MacAddress, Tap}; -use rand_ish::SimpleRng; use remain::sorted; use resources::{Alloc, MmioType, SystemAllocator}; use sync::{Condvar, Mutex}; @@ -54,10 +53,11 @@ use sys_util::{ use vhost; use vm_control::{ BalloonControlCommand, BalloonControlRequestSocket, BalloonControlResponseSocket, - DiskControlCommand, DiskControlRequestSocket, DiskControlResponseSocket, DiskControlResult, - UsbControlSocket, VmControlResponseSocket, VmIrqRequest, VmIrqResponse, VmIrqResponseSocket, - VmMemoryControlRequestSocket, VmMemoryControlResponseSocket, VmMemoryRequest, VmMemoryResponse, - VmRunMode, + BalloonControlResult, DiskControlCommand, DiskControlRequestSocket, DiskControlResponseSocket, + DiskControlResult, UsbControlSocket, VmControlResponseSocket, VmIrqRequest, VmIrqResponse, + VmIrqResponseSocket, VmMemoryControlRequestSocket, VmMemoryControlResponseSocket, + VmMemoryRequest, VmMemoryResponse, VmMsyncRequest, VmMsyncRequestSocket, VmMsyncResponse, + VmMsyncResponseSocket, VmRunMode, }; use crate::{Config, DiskOption, Executable, SharedDir, SharedDirKind, TouchDeviceOption}; @@ -119,8 +119,7 @@ pub enum Error { PmemDeviceNew(sys_util::Error), PollContextAdd(sys_util::Error), PollContextDelete(sys_util::Error), - ReadLowmemAvailable(io::Error), - ReadLowmemMargin(io::Error), + ReadMemAvailable(io::Error), RegisterBalloon(arch::DeviceRegistrationError), RegisterBlock(arch::DeviceRegistrationError), RegisterGpu(arch::DeviceRegistrationError), @@ -213,16 +212,7 @@ impl Display for Error { PmemDeviceNew(e) => write!(f, "failed to create pmem device: {}", e), PollContextAdd(e) => write!(f, "failed to add fd to poll context: {}", e), PollContextDelete(e) => write!(f, "failed to remove fd from poll context: {}", e), - ReadLowmemAvailable(e) => write!( - f, - "failed to read /sys/kernel/mm/chromeos-low_mem/available: {}", - e - ), - ReadLowmemMargin(e) => write!( - f, - "failed to read /sys/kernel/mm/chromeos-low_mem/margin: {}", - e - ), + ReadMemAvailable(e) => write!(f, "failed to read /proc/meminfo: {}", e), RegisterBalloon(e) => write!(f, "error registering balloon device: {}", e), RegisterBlock(e) => write!(f, "error registering block device: {}", e), RegisterGpu(e) => write!(f, "error registering gpu device: {}", e), @@ -265,6 +255,7 @@ enum TaggedControlSocket { Vm(VmControlResponseSocket), VmMemory(VmMemoryControlResponseSocket), VmIrq(VmIrqResponseSocket), + VmMsync(VmMsyncResponseSocket), } impl AsRef<UnixSeqpacket> for TaggedControlSocket { @@ -274,6 +265,7 @@ impl AsRef<UnixSeqpacket> for TaggedControlSocket { Vm(ref socket) => socket.as_ref(), VmMemory(ref socket) => socket.as_ref(), VmIrq(ref socket) => socket.as_ref(), + VmMsync(ref socket) => socket.as_ref(), } } } @@ -593,7 +585,13 @@ fn create_tap_net_device(cfg: &Config, tap_fd: RawFd) -> DeviceResult { .map_err(Error::CreateTapDevice)? }; - let dev = virtio::Net::from(tap).map_err(Error::NetDeviceNew)?; + let mut vq_pairs = cfg.net_vq_pairs.unwrap_or(1); + let vcpu_count = cfg.vcpu_count.unwrap_or(1); + if vcpu_count < vq_pairs as u32 { + error!("net vq pairs must be smaller than vcpu count, fall back to single queue mode"); + vq_pairs = 1; + } + let dev = virtio::Net::from(tap, vq_pairs).map_err(Error::NetDeviceNew)?; Ok(VirtioDeviceStub { dev: Box::new(dev), @@ -608,14 +606,21 @@ fn create_net_device( mac_address: MacAddress, mem: &GuestMemory, ) -> DeviceResult { + let mut vq_pairs = cfg.net_vq_pairs.unwrap_or(1); + let vcpu_count = cfg.vcpu_count.unwrap_or(1); + if vcpu_count < vq_pairs as u32 { + error!("net vq pairs must be smaller than vcpu count, fall back to single queue mode"); + vq_pairs = 1; + } + let dev = if cfg.vhost_net { let dev = virtio::vhost::Net::<Tap, vhost::Net<Tap>>::new(host_ip, netmask, mac_address, mem) .map_err(Error::VhostNetDeviceNew)?; Box::new(dev) as Box<dyn VirtioDevice> } else { - let dev = - virtio::Net::<Tap>::new(host_ip, netmask, mac_address).map_err(Error::NetDeviceNew)?; + let dev = virtio::Net::<Tap>::new(host_ip, netmask, mac_address, vq_pairs) + .map_err(Error::NetDeviceNew)?; Box::new(dev) as Box<dyn VirtioDevice> }; @@ -872,6 +877,7 @@ fn create_pmem_device( resources: &mut SystemAllocator, disk: &DiskOption, index: usize, + pmem_device_socket: VmMsyncRequestSocket, ) -> DeviceResult { let fd = OpenOptions::new() .read(true) @@ -933,16 +939,23 @@ fn create_pmem_device( ) .map_err(Error::AllocatePmemDeviceAddress)?; - vm.add_mmap_arena( + let slot = vm + .add_mmap_arena( + GuestAddress(mapping_address), + arena, + /* read_only = */ disk.read_only, + /* log_dirty_pages = */ false, + ) + .map_err(Error::AddPmemDeviceMemory)?; + + let dev = virtio::Pmem::new( + fd, GuestAddress(mapping_address), - arena, - /* read_only = */ disk.read_only, - /* log_dirty_pages = */ false, + slot, + arena_size, + Some(pmem_device_socket), ) - .map_err(Error::AddPmemDeviceMemory)?; - - let dev = virtio::Pmem::new(fd, GuestAddress(mapping_address), arena_size) - .map_err(Error::PmemDeviceNew)?; + .map_err(Error::PmemDeviceNew)?; Ok(VirtioDeviceStub { dev: Box::new(dev) as Box<dyn VirtioDevice>, @@ -962,6 +975,7 @@ fn create_virtio_devices( gpu_device_socket: VmMemoryControlRequestSocket, balloon_device_socket: BalloonControlResponseSocket, disk_device_sockets: &mut Vec<DiskControlResponseSocket>, + pmem_device_sockets: &mut Vec<VmMsyncRequestSocket>, ) -> DeviceResult<Vec<VirtioDeviceStub>> { let mut devs = Vec::new(); @@ -971,7 +985,15 @@ fn create_virtio_devices( } for (index, pmem_disk) in cfg.pmem_devices.iter().enumerate() { - devs.push(create_pmem_device(cfg, vm, resources, pmem_disk, index)?); + let pmem_device_socket = pmem_device_sockets.remove(0); + devs.push(create_pmem_device( + cfg, + vm, + resources, + pmem_disk, + index, + pmem_device_socket, + )?); } devs.push(create_rng_device(cfg)?); @@ -1122,6 +1144,7 @@ fn create_devices( gpu_device_socket: VmMemoryControlRequestSocket, balloon_device_socket: BalloonControlResponseSocket, disk_device_sockets: &mut Vec<DiskControlResponseSocket>, + pmem_device_sockets: &mut Vec<VmMsyncRequestSocket>, usb_provider: HostBackendDeviceProvider, ) -> DeviceResult<Vec<(Box<dyn PciDevice>, Option<Minijail>)>> { let stubs = create_virtio_devices( @@ -1134,6 +1157,7 @@ fn create_devices( gpu_device_socket, balloon_device_socket, disk_device_sockets, + pmem_device_sockets, )?; let mut pci_devices = Vec::new(); @@ -1496,9 +1520,9 @@ fn run_vcpu( .map_err(Error::SpawnVcpu) } -// Reads the contents of a file and converts the space-separated fields into a Vec of u64s. +// Reads the contents of a file and converts the space-separated fields into a Vec of i64s. // Returns an error if any of the fields fail to parse. -fn file_fields_to_u64<P: AsRef<Path>>(path: P) -> io::Result<Vec<u64>> { +fn file_fields_to_i64<P: AsRef<Path>>(path: P) -> io::Result<Vec<i64>> { let mut file = File::open(path)?; let mut buf = [0u8; 32]; @@ -1510,7 +1534,7 @@ fn file_fields_to_u64<P: AsRef<Path>>(path: P) -> io::Result<Vec<u64>> { .trim() .split_whitespace() .map(|x| { - x.parse::<u64>() + x.parse::<i64>() .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) }) .collect() @@ -1518,8 +1542,8 @@ fn file_fields_to_u64<P: AsRef<Path>>(path: P) -> io::Result<Vec<u64>> { // Reads the contents of a file and converts them into a u64, and if there // are multiple fields it only returns the first one. -fn file_to_u64<P: AsRef<Path>>(path: P) -> io::Result<u64> { - file_fields_to_u64(path)? +fn file_to_i64<P: AsRef<Path>>(path: P) -> io::Result<i64> { + file_fields_to_i64(path)? .into_iter() .next() .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "empty file")) @@ -1589,7 +1613,8 @@ pub fn run_config(cfg: Config) -> Result<()> { control_sockets.push(TaggedControlSocket::VmMemory(wayland_host_socket)); // Balloon gets a special socket so balloon requests can be forwarded from the main process. let (balloon_host_socket, balloon_device_socket) = - msg_socket::pair::<BalloonControlCommand, ()>().map_err(Error::CreateSocket)?; + msg_socket::pair::<BalloonControlCommand, BalloonControlResult>() + .map_err(Error::CreateSocket)?; // Create one control socket per disk. let mut disk_device_sockets = Vec::new(); @@ -1603,6 +1628,15 @@ pub fn run_config(cfg: Config) -> Result<()> { disk_device_sockets.push(disk_device_socket); } + let mut pmem_device_sockets = Vec::new(); + let pmem_count = cfg.pmem_devices.len(); + for _ in 0..pmem_count { + let (pmem_host_socket, pmem_device_socket) = + msg_socket::pair::<VmMsyncResponse, VmMsyncRequest>().map_err(Error::CreateSocket)?; + pmem_device_sockets.push(pmem_device_socket); + control_sockets.push(TaggedControlSocket::VmMsync(pmem_host_socket)); + } + let (gpu_host_socket, gpu_device_socket) = msg_socket::pair::<VmMemoryResponse, VmMemoryRequest>().map_err(Error::CreateSocket)?; control_sockets.push(TaggedControlSocket::VmMemory(gpu_host_socket)); @@ -1630,6 +1664,7 @@ pub fn run_config(cfg: Config) -> Result<()> { gpu_device_socket, balloon_device_socket, &mut disk_device_sockets, + &mut pmem_device_sockets, usb_provider, ) }, @@ -1658,35 +1693,16 @@ fn run_control( sigchld_fd: SignalFd, sandbox: bool, ) -> Result<()> { - // Paths to get the currently available memory and the low memory threshold. - const LOWMEM_MARGIN: &str = "/sys/kernel/mm/chromeos-low_mem/margin"; const LOWMEM_AVAILABLE: &str = "/sys/kernel/mm/chromeos-low_mem/available"; - // The amount of additional memory to claim back from the VM whenever the system is - // low on memory. - const ONE_GB: u64 = (1 << 30); - - let max_balloon_memory = match linux.vm.get_memory().memory_size() { - // If the VM has at least 1.5 GB, the balloon driver can consume all but the last 1 GB. - n if n >= (ONE_GB / 2) * 3 => n - ONE_GB, - // Otherwise, if the VM has at least 500MB the balloon driver will consume at most - // half of it. - n if n >= (ONE_GB / 2) => n / 2, - // Otherwise, the VM is too small for us to take memory away from it. - _ => 0, - }; - let mut current_balloon_memory: u64 = 0; - let balloon_memory_increment: u64 = max_balloon_memory / 16; - #[derive(PollToken)] enum Token { Exit, Suspend, ChildSignal, - CheckAvailableMemory, IrqFd { gsi: usize }, - LowMemory, - LowmemTimer, + BalanceMemory, + BalloonResult, VmControlServer, VmControl { index: usize }, } @@ -1713,28 +1729,6 @@ fn run_control( .map_err(Error::PollContextAdd)?; } - // Watch for low memory notifications and take memory back from the VM. - let low_mem = File::open("/dev/chromeos-low-mem").ok(); - if let Some(low_mem) = &low_mem { - poll_ctx - .add(low_mem, Token::LowMemory) - .map_err(Error::PollContextAdd)?; - } else { - warn!("Unable to open low mem indicator, maybe not a chrome os kernel"); - } - - // Used to rate limit balloon requests. - let mut lowmem_timer = TimerFd::new().map_err(Error::CreateTimerFd)?; - poll_ctx - .add(&lowmem_timer, Token::LowmemTimer) - .map_err(Error::PollContextAdd)?; - - // Used to check whether it's ok to start giving memory back to the VM. - let mut freemem_timer = TimerFd::new().map_err(Error::CreateTimerFd)?; - poll_ctx - .add(&freemem_timer, Token::CheckAvailableMemory) - .map_err(Error::PollContextAdd)?; - if let Some(gsi_relay) = &linux.gsi_relay { for (gsi, evt) in gsi_relay.irqfd.iter().enumerate() { if let Some(evt) = evt { @@ -1745,14 +1739,26 @@ fn run_control( } } - // Used to add jitter to timer values so that we don't have a thundering herd problem when - // multiple VMs are running. - let mut simple_rng = SimpleRng::new( - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("time went backwards") - .subsec_nanos() as u64, - ); + // Balance available memory between guest and host every second. + let mut balancemem_timer = TimerFd::new().map_err(Error::CreateTimerFd)?; + if Path::new(LOWMEM_AVAILABLE).exists() { + // Create timer request balloon stats every 1s. + poll_ctx + .add(&balancemem_timer, Token::BalanceMemory) + .map_err(Error::PollContextAdd)?; + let balancemem_dur = Duration::from_secs(1); + let balancemem_int = Duration::from_secs(1); + balancemem_timer + .reset(balancemem_dur, Some(balancemem_int)) + .map_err(Error::ResetTimerFd)?; + + // Listen for balloon statistics from the guest so we can balance. + poll_ctx + .add(&balloon_host_socket, Token::BalloonResult) + .map_err(Error::PollContextAdd)?; + } else { + warn!("Unable to open low mem available, maybe not a chrome os kernel"); + } if sandbox { // Before starting VCPUs, in case we started with some capabilities, drop them all. @@ -1845,39 +1851,6 @@ fn run_control( } break 'poll; } - Token::CheckAvailableMemory => { - // Acknowledge the timer. - freemem_timer.wait().map_err(Error::TimerFd)?; - if current_balloon_memory == 0 { - // Nothing to see here. - if let Err(e) = freemem_timer.clear() { - warn!("unable to clear available memory check timer: {}", e); - } - continue; - } - - // Otherwise see if we can free up some memory. - let margin = file_to_u64(LOWMEM_MARGIN).map_err(Error::ReadLowmemMargin)?; - let available = - file_to_u64(LOWMEM_AVAILABLE).map_err(Error::ReadLowmemAvailable)?; - - // `available` and `margin` are specified in MB while `balloon_memory_increment` is in - // bytes. So to correctly compare them we need to turn the increment value into MB. - if available >= margin + 2 * (balloon_memory_increment >> 20) { - current_balloon_memory = - if current_balloon_memory >= balloon_memory_increment { - current_balloon_memory - balloon_memory_increment - } else { - 0 - }; - let command = BalloonControlCommand::Adjust { - num_bytes: current_balloon_memory, - }; - if let Err(e) = balloon_host_socket.send(&command) { - warn!("failed to send memory value to balloon device: {}", e); - } - } - } Token::IrqFd { gsi } => { if let Some((pic, ioapic)) = &linux.split_irqchip { // This will never fail because gsi_relay is Some iff split_irqchip is @@ -1919,52 +1892,76 @@ fn run_control( panic!("split irqchip not found, should be impossible."); } } - Token::LowMemory => { - if let Some(low_mem) = &low_mem { - let old_balloon_memory = current_balloon_memory; - current_balloon_memory = min( - current_balloon_memory + balloon_memory_increment, - max_balloon_memory, - ); - if current_balloon_memory != old_balloon_memory { - let command = BalloonControlCommand::Adjust { - num_bytes: current_balloon_memory, + Token::BalanceMemory => { + balancemem_timer.wait().map_err(Error::TimerFd)?; + let command = BalloonControlCommand::Stats {}; + if let Err(e) = balloon_host_socket.send(&command) { + warn!("failed to send stats request to balloon device: {}", e); + } + } + Token::BalloonResult => { + match balloon_host_socket.recv() { + Ok(BalloonControlResult::Stats { + stats, + balloon_actual: balloon_actual_u, + }) => { + // Available memory is reported in MB, and we need bytes. + let host_available = file_to_i64(LOWMEM_AVAILABLE) + .map_err(Error::ReadMemAvailable)? + << 20; + let guest_available_u = if let Some(available) = stats.available_memory + { + available + } else { + warn!("guest available_memory stat is missing"); + continue; }; - if let Err(e) = balloon_host_socket.send(&command) { - warn!("failed to send memory value to balloon device: {}", e); + if guest_available_u > i64::max_value() as u64 { + warn!("guest available memory is too large"); + continue; + } + if balloon_actual_u > i64::max_value() as u64 { + warn!("actual balloon size is too large"); + continue; + } + // Guest and host available memory is balanced equally. + const GUEST_SHARE: i64 = 1; + const HOST_SHARE: i64 = 1; + // Tell the guest to change the balloon size if the + // target balloon size is more than 5% different + // from the current balloon size. + const RESIZE_PERCENT: i64 = 5; + let balloon_actual = balloon_actual_u as i64; + let guest_available = guest_available_u as i64; + // Compute how much memory the guest should have + // available after we rebalance. + let guest_available_target = (GUEST_SHARE + * (guest_available + host_available)) + / (GUEST_SHARE + HOST_SHARE); + let guest_available_delta = guest_available_target - guest_available; + // How much do we have to change the balloon to + // balance. + let balloon_target = max(balloon_actual - guest_available_delta, 0); + // Compute the change in balloon size in percent. + // If the balloon size is 0, use 1 so we don't + // overflow from the infinity % increase. + let balloon_change_percent = (balloon_actual - balloon_target).abs() + * 100 + / max(balloon_actual, 1); + + if balloon_change_percent >= RESIZE_PERCENT { + let command = BalloonControlCommand::Adjust { + num_bytes: balloon_target as u64, + }; + if let Err(e) = balloon_host_socket.send(&command) { + warn!("failed to send memory value to balloon device: {}", e); + } } } - - // Stop polling the lowmem device until the timer fires. - poll_ctx.delete(low_mem).map_err(Error::PollContextDelete)?; - - // Add some jitter to the timer so that if there are multiple VMs running - // they don't all start ballooning at exactly the same time. - let lowmem_dur = Duration::from_millis(1000 + simple_rng.rng() % 200); - lowmem_timer - .reset(lowmem_dur, None) - .map_err(Error::ResetTimerFd)?; - - // Also start a timer to check when we can start giving memory back. Do the - // first check after a minute (with jitter) and subsequent checks after - // every 30 seconds (with jitter). - let freemem_dur = Duration::from_secs(60 + simple_rng.rng() % 12); - let freemem_int = Duration::from_secs(30 + simple_rng.rng() % 6); - freemem_timer - .reset(freemem_dur, Some(freemem_int)) - .map_err(Error::ResetTimerFd)?; - } - } - Token::LowmemTimer => { - // Acknowledge the timer. - lowmem_timer.wait().map_err(Error::TimerFd)?; - - if let Some(low_mem) = &low_mem { - // Start polling the lowmem device again. - poll_ctx - .add(low_mem, Token::LowMemory) - .map_err(Error::PollContextAdd)?; - } + Err(e) => { + error!("failed to recv BalloonControlResult: {}", e); + } + }; } Token::VmControlServer => { if let Some(socket_server) = &control_server_socket { @@ -2066,6 +2063,21 @@ fn run_control( } } }, + TaggedControlSocket::VmMsync(socket) => match socket.recv() { + Ok(request) => { + let response = request.execute(&mut linux.vm); + if let Err(e) = socket.send(&response) { + error!("failed to send VmMsyncResponse: {}", e); + } + } + Err(e) => { + if let MsgError::BadRecvSize { actual: 0, .. } = e { + vm_control_indices_to_remove.push(index); + } else { + error!("failed to recv VmMsyncRequest: {}", e); + } + } + }, } } } @@ -2077,10 +2089,9 @@ fn run_control( Token::Exit => {} Token::Suspend => {} Token::ChildSignal => {} - Token::CheckAvailableMemory => {} Token::IrqFd { gsi: _ } => {} - Token::LowMemory => {} - Token::LowmemTimer => {} + Token::BalanceMemory => {} + Token::BalloonResult => {} Token::VmControlServer => {} Token::VmControl { index } => { // It's possible more data is readable and buffered while the socket is hungup, diff --git a/src/main.rs b/src/main.rs index d385db3..e88297e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -762,6 +762,26 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: })?, ) } + "net-vq-pairs" => { + if cfg.net_vq_pairs.is_some() { + return Err(argument::Error::TooManyArguments( + "`net-vq-pairs` already given".to_owned(), + )); + } + cfg.net_vq_pairs = + Some( + value + .unwrap() + .parse() + .map_err(|_| argument::Error::InvalidValue { + value: value.unwrap().to_owned(), + expected: String::from( + "this value for `net-vq-pairs` needs to be integer", + ), + })?, + ) + } + "wayland-sock" => { let mut components = value.unwrap().split(','); let path = @@ -1354,6 +1374,14 @@ Capture keyboard input from the display window. "Capture keyboard input from the display window.", ), Argument::value( + "net-vq-pairs", + "N", + "\ +Virtio net virtual queue paris. +(default: 1) +", + ), + Argument::value( "wayland-sock", "PATH[,name=NAME]", "\ diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index 1c7027f..ae7e19c 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -662,7 +662,7 @@ pub fn run_config(cfg: Config) -> Result<()> { if let Some(host_ip) = cfg.host_ip { if let Some(netmask) = cfg.netmask { if let Some(mac_address) = cfg.mac_address { - let tap = Tap::new(false).map_err(Error::TapOpen)?; + let tap = Tap::new(false, false).map_err(Error::TapOpen)?; tap.set_ip_addr(host_ip).map_err(Error::TapSetIp)?; tap.set_netmask(netmask).map_err(Error::TapSetNetmask)?; tap.set_mac_address(mac_address) diff --git a/src/plugin/process.rs b/src/plugin/process.rs index ea7a78c..51fc892 100644 --- a/src/plugin/process.rs +++ b/src/plugin/process.rs @@ -361,7 +361,7 @@ impl Process { None => return Err(SysError::new(EOVERFLOW)), _ => {} } - let mem = MemoryMapping::from_fd_offset(&shm, length as usize, offset as usize) + let mem = MemoryMapping::from_fd_offset(&shm, length as usize, offset) .map_err(mmap_to_sys_err)?; let slot = vm.add_mmio_memory(GuestAddress(start), mem, read_only, dirty_log)?; entry.insert(PluginObject::Memory { |