From e13b180f74ad6d0b1cb1db2a198e294da97e526c Mon Sep 17 00:00:00 2001 From: Jingkui Wang Date: Wed, 3 Oct 2018 13:04:47 -0700 Subject: crosvm: use msg_socket in vm_control Refactor existing code to use msg_socket. BUG=None TEST=local build and run Change-Id: Iee72326b330e035303f679e1aedd6e5d18ad4f8a Reviewed-on: https://chromium-review.googlesource.com/1260260 Commit-Ready: Jingkui Wang Tested-by: Jingkui Wang Reviewed-by: Zach Reizner --- Cargo.lock | 3 + devices/src/virtio/wl.rs | 15 +- kvm/Cargo.toml | 1 + kvm/src/lib.rs | 4 +- resources/Cargo.toml | 1 + resources/src/gpu_allocator.rs | 5 +- resources/src/lib.rs | 2 + src/linux.rs | 17 +- src/main.rs | 8 +- vm_control/Cargo.toml | 1 + vm_control/src/lib.rs | 530 +++-------------------------------------- 11 files changed, 67 insertions(+), 520 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6f8784..0bc80ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,6 +219,7 @@ version = "0.1.0" dependencies = [ "kvm_sys 0.1.0", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "msg_socket 0.1.0", "sys_util 0.1.0", ] @@ -373,6 +374,7 @@ dependencies = [ "data_model 0.1.0", "gpu_buffer 0.1.0", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "msg_socket 0.1.0", "sys_util 0.1.0", ] @@ -438,6 +440,7 @@ dependencies = [ "data_model 0.1.0", "kvm 0.1.0", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "msg_socket 0.1.0", "resources 0.1.0", "sys_util 0.1.0", ] diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs index 0b973bd..7b9ffc8 100644 --- a/devices/src/virtio/wl.rs +++ b/devices/src/virtio/wl.rs @@ -56,6 +56,7 @@ use libc::{dup, EBADF, EINVAL}; use data_model::VolatileMemoryError; use data_model::*; +use msg_socket::{MsgError, MsgReceiver, MsgSender, MsgSocket}; use resources::GpuMemoryDesc; use sys_util::{ pipe, round_up_to_page_size, Error, EventFd, FileFlags, GuestAddress, GuestMemory, @@ -66,7 +67,7 @@ use sys_util::{ use sys_util::ioctl_with_ref; use super::{DescriptorChain, Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_WL}; -use vm_control::{MaybeOwnedFd, VmControlError, VmRequest, VmResponse}; +use vm_control::{MaybeOwnedFd, VmRequest, VmResponse}; const VIRTWL_SEND_MAX_ALLOCS: usize = 28; const VIRTIO_WL_CMD_VFD_NEW: u32 = 256; @@ -409,7 +410,7 @@ enum WlError { AllocSetSize(Error), SocketConnect(io::Error), SocketNonBlock(io::Error), - VmControl(VmControlError), + VmControl(MsgError), VmBadResponse, CheckedOffset, GuestMemory(GuestMemoryError), @@ -467,21 +468,23 @@ impl From for WlError { #[derive(Clone)] struct VmRequester { - inner: Rc>, + inner: Rc>>, } impl VmRequester { fn new(vm_socket: UnixDatagram) -> VmRequester { VmRequester { - inner: Rc::new(RefCell::new(vm_socket)), + inner: Rc::new(RefCell::new(MsgSocket::::new( + vm_socket, + ))), } } fn request(&self, request: VmRequest) -> WlResult { let mut inner = self.inner.borrow_mut(); let ref mut vm_socket = *inner; - request.send(vm_socket).map_err(WlError::VmControl)?; - VmResponse::recv(vm_socket).map_err(WlError::VmControl) + vm_socket.send(&request).map_err(WlError::VmControl)?; + vm_socket.recv().map_err(WlError::VmControl) } } diff --git a/kvm/Cargo.toml b/kvm/Cargo.toml index 11afad4..2281598 100644 --- a/kvm/Cargo.toml +++ b/kvm/Cargo.toml @@ -7,3 +7,4 @@ authors = ["The Chromium OS Authors"] libc = "*" kvm_sys = { path = "../kvm_sys" } sys_util = { path = "../sys_util" } +msg_socket = { path = "../msg_socket" } diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs index 050e1cd..72bea5e 100644 --- a/kvm/src/lib.rs +++ b/kvm/src/lib.rs @@ -8,6 +8,7 @@ extern crate kvm_sys; extern crate libc; #[macro_use] extern crate sys_util; +extern crate msg_socket; mod cap; @@ -25,6 +26,7 @@ use libc::{open, EINVAL, ENOENT, ENOSPC, O_CLOEXEC, O_RDWR}; use kvm_sys::*; +use msg_socket::MsgOnSocket; #[allow(unused_imports)] use sys_util::{ ioctl, ioctl_with_mut_ptr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val, @@ -239,7 +241,7 @@ impl AsRawFd for Kvm { } /// An address either in programmable I/O space or in memory mapped I/O space. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, MsgOnSocket)] pub enum IoeventAddress { Pio(u64), Mmio(u64), diff --git a/resources/Cargo.toml b/resources/Cargo.toml index 29fc38a..c563d20 100644 --- a/resources/Cargo.toml +++ b/resources/Cargo.toml @@ -11,3 +11,4 @@ data_model = { path = "../data_model" } gpu_buffer = { path = "../gpu_buffer", optional = true } libc = "*" sys_util = { path = "../sys_util" } +msg_socket = { path = "../msg_socket" } diff --git a/resources/src/gpu_allocator.rs b/resources/src/gpu_allocator.rs index 9f98bcf..16dc944 100644 --- a/resources/src/gpu_allocator.rs +++ b/resources/src/gpu_allocator.rs @@ -9,6 +9,7 @@ use libc::EINVAL; #[cfg(feature = "wl-dmabuf")] use gpu_buffer; +use msg_socket::MsgOnSocket; use sys_util; #[derive(Debug)] @@ -18,14 +19,14 @@ pub enum GpuAllocatorError { } /// Struct that describes the offset and stride of a plane located in GPU memory. -#[derive(Clone, Copy, Debug, PartialEq, Default)] +#[derive(Clone, Copy, Debug, PartialEq, Default, MsgOnSocket)] pub struct GpuMemoryPlaneDesc { pub stride: u32, pub offset: u32, } /// Struct that describes a GPU memory allocation that consists of up to 3 planes. -#[derive(Clone, Copy, Debug, Default)] +#[derive(Clone, Copy, Debug, Default, MsgOnSocket)] pub struct GpuMemoryDesc { pub planes: [GpuMemoryPlaneDesc; 3], } diff --git a/resources/src/lib.rs b/resources/src/lib.rs index 5d12cfc..e19ac7c 100644 --- a/resources/src/lib.rs +++ b/resources/src/lib.rs @@ -8,6 +8,8 @@ extern crate gpu_buffer; extern crate libc; extern crate sys_util; +#[macro_use] +extern crate msg_socket; mod address_allocator; mod gpu_allocator; diff --git a/src/linux.rs b/src/linux.rs index 40f32a1..44c2aef 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -28,12 +28,13 @@ use byteorder::{ByteOrder, LittleEndian}; use devices::{self, PciDevice, VirtioPciDevice}; use io_jail::{self, Minijail}; use kvm::*; +use msg_socket::{MsgReceiver, MsgSender, UnlinkMsgSocket}; use net_util::Tap; use qcow::{self, ImageType, QcowFile}; use sys_util; use sys_util::*; use vhost; -use vm_control::VmRequest; +use vm_control::{VmRequest, VmResponse}; use Config; @@ -788,11 +789,15 @@ pub fn run_config(cfg: Config) -> Result<()> { if let Some(ref path_string) = cfg.socket_path { let path = Path::new(path_string); let dgram = UnixDatagram::bind(path).map_err(Error::CreateSocket)?; - control_sockets.push(UnlinkUnixDatagram(dgram)); + control_sockets.push(UnlinkMsgSocket::::new( + UnlinkUnixDatagram(dgram), + )); }; let (wayland_host_socket, wayland_device_socket) = UnixDatagram::pair().map_err(Error::CreateSocket)?; - control_sockets.push(UnlinkUnixDatagram(wayland_host_socket)); + control_sockets.push(UnlinkMsgSocket::::new( + UnlinkUnixDatagram(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) = UnixDatagram::pair().map_err(Error::CreateSocket)?; @@ -805,7 +810,7 @@ pub fn run_config(cfg: Config) -> Result<()> { fn run_control( mut linux: RunnableLinuxVm, - control_sockets: Vec, + control_sockets: Vec>, balloon_host_socket: UnixDatagram, sigchld_fd: SignalFd, ) -> Result<()> { @@ -1045,7 +1050,7 @@ fn run_control( } Token::VmControl { index } => { if let Some(socket) = control_sockets.get(index as usize) { - match VmRequest::recv(socket.as_ref()) { + match socket.recv() { Ok(request) => { let mut running = true; let response = request.execute( @@ -1054,7 +1059,7 @@ fn run_control( &mut running, &balloon_host_socket, ); - if let Err(e) = response.send(socket.as_ref()) { + if let Err(e) = socket.send(&response) { error!("failed to send VmResponse: {:?}", e); } if !running { diff --git a/src/main.rs b/src/main.rs index 7158f67..75ad172 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ extern crate sys_util; extern crate data_model; #[cfg(feature = "wl-dmabuf")] extern crate gpu_buffer; +extern crate msg_socket; #[cfg(feature = "plugin")] extern crate plugin_proto; #[cfg(feature = "plugin")] @@ -51,6 +52,7 @@ use qcow::QcowFile; use sys_util::{getpid, kill_process_group, reap_child, syslog}; use argument::{print_help, set_arguments, Argument}; +use msg_socket::{MsgSender, Sender}; use vm_control::VmRequest; static SECCOMP_POLICY_DIR: &'static str = "/usr/share/policy/crosvm"; @@ -549,7 +551,8 @@ fn stop_vms(args: std::env::Args) -> std::result::Result<(), ()> { Ok(s) }) { Ok(s) => { - if let Err(e) = VmRequest::Exit.send(&s) { + let sender = Sender::::new(s); + if let Err(e) = sender.send(&VmRequest::Exit) { error!( "failed to send stop request to socket at '{}': {:?}", socket_path, e @@ -586,7 +589,8 @@ fn balloon_vms(mut args: std::env::Args) -> std::result::Result<(), ()> { Ok(s) }) { Ok(s) => { - if let Err(e) = VmRequest::BalloonAdjust(num_pages).send(&s) { + let sender = Sender::::new(s); + if let Err(e) = sender.send(&VmRequest::BalloonAdjust(num_pages)) { error!( "failed to send balloon request to socket at '{}': {:?}", socket_path, e diff --git a/vm_control/Cargo.toml b/vm_control/Cargo.toml index c2f6e40..5e03b9e 100644 --- a/vm_control/Cargo.toml +++ b/vm_control/Cargo.toml @@ -10,3 +10,4 @@ kvm = { path = "../kvm" } libc = "*" sys_util = { path = "../sys_util" } resources = { path = "../resources" } +msg_socket = { path = "../msg_socket" } diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs index 4d1d036..deec07d 100644 --- a/vm_control/src/lib.rs +++ b/vm_control/src/lib.rs @@ -11,45 +11,24 @@ //! if the request type expects one. extern crate byteorder; -extern crate data_model; extern crate kvm; extern crate libc; +extern crate msg_socket; extern crate resources; extern crate sys_util; use std::fs::File; use std::io::{Seek, SeekFrom}; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::net::UnixDatagram; -use std::result; -use libc::{EINVAL, ENODEV, ERANGE}; +use libc::{EINVAL, ENODEV}; use byteorder::{LittleEndian, WriteBytesExt}; -use data_model::{DataInit, Le32, Le64, VolatileMemory}; use kvm::{Datamatch, IoeventAddress, Vm}; -use resources::{GpuMemoryDesc, GpuMemoryPlaneDesc, SystemAllocator}; -use sys_util::{ - Error as SysError, EventFd, GuestAddress, MemoryMapping, MmapError, Result, ScmSocket, -}; - -#[derive(Debug, PartialEq)] -/// An error during a request or response transaction. -pub enum VmControlError { - /// Error while sending a request or response. - Send(SysError), - /// Error while receiving a request or response. - Recv(SysError), - /// The type of a received request or response is unknown. - InvalidType, - /// There was not the expected amount of data when receiving a request or response. The inner - /// value is how much data was read. - BadSize(usize), - /// There was no associated file descriptor received for a request that expected it. - ExpectFd, -} - -pub type VmControlResult = result::Result; +use msg_socket::{MsgOnSocket, MsgResult}; +use resources::{GpuMemoryDesc, SystemAllocator}; +use sys_util::{Error as SysError, EventFd, GuestAddress, MemoryMapping, MmapError, Result}; /// A file descriptor either borrowed or owned by this. pub enum MaybeOwnedFd { @@ -68,9 +47,29 @@ impl AsRawFd for MaybeOwnedFd { } } +// When sent, it could be owned or borrowed. On the receiver end, it always owned. +impl MsgOnSocket for MaybeOwnedFd { + fn msg_size() -> usize { + 0usize + } + fn max_fd_count() -> usize { + 1usize + } + unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> { + let (fd, size) = RawFd::read_from_buffer(buffer, fds)?; + let file = File::from_raw_fd(fd); + Ok((MaybeOwnedFd::Owned(file), size)) + } + fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult { + let fd = self.as_raw_fd(); + fd.write_to_buffer(buffer, fds) + } +} + /// A request to the main process to perform some operation on the VM. /// /// Unless otherwise noted, each request should expect a `VmResponse::Ok` to be received on success. +#[derive(MsgOnSocket)] pub enum VmRequest { /// Try to grow or shrink the VM's balloon. BalloonAdjust(i32), @@ -94,28 +93,6 @@ pub enum VmRequest { }, } -const VM_REQUEST_TYPE_EXIT: u32 = 1; -const VM_REQUEST_TYPE_REGISTER_MEMORY: u32 = 2; -const VM_REQUEST_TYPE_UNREGISTER_MEMORY: u32 = 3; -const VM_REQUEST_TYPE_BALLOON_ADJUST: u32 = 4; -const VM_REQUEST_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY: u32 = 5; -const VM_REQUEST_SIZE: usize = 32; - -#[repr(C)] -#[derive(Clone, Copy, Default)] -struct VmRequestStruct { - type_: Le32, - slot: Le32, - size: Le64, - num_pages: Le32, - width: Le32, - height: Le32, - format: Le32, -} - -// Safe because it only has data and has no implicit padding. -unsafe impl DataInit for VmRequestStruct {} - fn register_memory( vm: &mut Vm, allocator: &mut SystemAllocator, @@ -140,90 +117,6 @@ fn register_memory( } impl VmRequest { - /// Receive a `VmRequest` from the given socket. - /// - /// A `VmResponse` should be sent out over the given socket before another request is received. - pub fn recv(s: &UnixDatagram) -> VmControlResult { - assert_eq!(VM_REQUEST_SIZE, std::mem::size_of::()); - let mut buf = [0; VM_REQUEST_SIZE]; - let (read, file) = s - .recv_with_fd(&mut buf) - .map_err(|e| VmControlError::Recv(e))?; - if read != VM_REQUEST_SIZE { - return Err(VmControlError::BadSize(read)); - } - // The unwrap() will never fail because it's referencing a buf statically sized to be large - // enough for a VmRequestStruct. - let req: VmRequestStruct = buf.as_mut().get_ref(0).unwrap().load(); - - match req.type_.into() { - VM_REQUEST_TYPE_EXIT => Ok(VmRequest::Exit), - VM_REQUEST_TYPE_REGISTER_MEMORY => { - let fd = file.ok_or(VmControlError::ExpectFd)?; - Ok(VmRequest::RegisterMemory( - MaybeOwnedFd::Owned(fd), - req.size.to_native() as usize, - )) - } - VM_REQUEST_TYPE_UNREGISTER_MEMORY => Ok(VmRequest::UnregisterMemory(req.slot.into())), - VM_REQUEST_TYPE_BALLOON_ADJUST => { - Ok(VmRequest::BalloonAdjust(req.num_pages.to_native() as i32)) - } - VM_REQUEST_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY => { - Ok(VmRequest::AllocateAndRegisterGpuMemory { - width: req.width.to_native(), - height: req.height.to_native(), - format: req.format.to_native(), - }) - } - _ => Err(VmControlError::InvalidType), - } - } - - /// Send a `VmRequest` over the given socket. - /// - /// After this request is a sent, a `VmResponse` should be received before sending another - /// request. - pub fn send(&self, s: &UnixDatagram) -> VmControlResult<()> { - assert_eq!(VM_REQUEST_SIZE, std::mem::size_of::()); - let mut req = VmRequestStruct::default(); - let mut fd_buf = [0; 1]; - let mut fd_len = 0; - match self { - &VmRequest::Exit => req.type_ = Le32::from(VM_REQUEST_TYPE_EXIT), - &VmRequest::RegisterMemory(ref fd, size) => { - req.type_ = Le32::from(VM_REQUEST_TYPE_REGISTER_MEMORY); - req.size = Le64::from(size as u64); - fd_buf[0] = fd.as_raw_fd(); - fd_len = 1; - } - &VmRequest::UnregisterMemory(slot) => { - req.type_ = Le32::from(VM_REQUEST_TYPE_UNREGISTER_MEMORY); - req.slot = Le32::from(slot); - } - &VmRequest::BalloonAdjust(pages) => { - req.type_ = Le32::from(VM_REQUEST_TYPE_BALLOON_ADJUST); - req.num_pages = Le32::from(pages as u32); - } - &VmRequest::AllocateAndRegisterGpuMemory { - width, - height, - format, - } => { - req.type_ = Le32::from(VM_REQUEST_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY); - req.width = Le32::from(width as u32); - req.height = Le32::from(height as u32); - req.format = Le32::from(format as u32); - } - _ => return Err(VmControlError::InvalidType), - } - let mut buf = [0; VM_REQUEST_SIZE]; - buf.as_mut().get_ref(0).unwrap().store(req); - s.send_with_fds(buf.as_ref(), &fd_buf[..fd_len]) - .map_err(|e| VmControlError::Send(e))?; - Ok(()) - } - /// Executes this request on the given Vm and other mutable state. /// /// # Arguments @@ -313,6 +206,7 @@ impl VmRequest { /// Indication of success or failure of a `VmRequest`. /// /// Success is usually indicated `VmResponse::Ok` unless there is data associated with the response. +#[derive(MsgOnSocket)] pub enum VmResponse { /// Indicates the request was executed successfully. Ok, @@ -330,373 +224,3 @@ pub enum VmResponse { desc: GpuMemoryDesc, }, } - -const VM_RESPONSE_TYPE_OK: u32 = 1; -const VM_RESPONSE_TYPE_ERR: u32 = 2; -const VM_RESPONSE_TYPE_REGISTER_MEMORY: u32 = 3; -const VM_RESPONSE_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY: u32 = 4; -const VM_RESPONSE_SIZE: usize = 48; - -#[repr(C)] -#[derive(Clone, Copy, Default)] -struct VmResponseStruct { - type_: Le32, - errno: Le32, - pfn: Le64, - slot: Le32, - stride0: Le32, - stride1: Le32, - stride2: Le32, - offset0: Le32, - offset1: Le32, - offset2: Le32, -} - -// Safe because it only has data and has no implicit padding. -unsafe impl DataInit for VmResponseStruct {} - -impl VmResponse { - /// Receive a `VmResponse` from the given socket. - /// - /// This should be called after the sending a `VmRequest` before sending another request. - pub fn recv(s: &UnixDatagram) -> VmControlResult { - let mut buf = [0; VM_RESPONSE_SIZE]; - let (read, file) = s - .recv_with_fd(&mut buf) - .map_err(|e| VmControlError::Recv(e))?; - if read != VM_RESPONSE_SIZE { - return Err(VmControlError::BadSize(read)); - } - let resp: VmResponseStruct = buf.as_mut().get_ref(0).unwrap().load(); - - match resp.type_.into() { - VM_RESPONSE_TYPE_OK => Ok(VmResponse::Ok), - VM_RESPONSE_TYPE_ERR => Ok(VmResponse::Err(SysError::new( - resp.errno.to_native() as i32 - ))), - VM_RESPONSE_TYPE_REGISTER_MEMORY => Ok(VmResponse::RegisterMemory { - pfn: resp.pfn.into(), - slot: resp.slot.into(), - }), - VM_RESPONSE_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY => { - let fd = file.ok_or(VmControlError::ExpectFd)?; - Ok(VmResponse::AllocateAndRegisterGpuMemory { - fd: MaybeOwnedFd::Owned(fd), - pfn: resp.pfn.into(), - slot: resp.slot.into(), - desc: GpuMemoryDesc { - planes: [ - GpuMemoryPlaneDesc { - stride: resp.stride0.into(), - offset: resp.offset0.into(), - }, - GpuMemoryPlaneDesc { - stride: resp.stride1.into(), - offset: resp.offset1.into(), - }, - GpuMemoryPlaneDesc { - stride: resp.stride2.into(), - offset: resp.offset2.into(), - }, - ], - }, - }) - } - _ => Err(VmControlError::InvalidType), - } - } - - /// Send a `VmResponse` over the given socket. - /// - /// This must be called after receiving a `VmRequest` to indicate the outcome of that request's - /// execution. - pub fn send(&self, s: &UnixDatagram) -> VmControlResult<()> { - let mut resp = VmResponseStruct::default(); - let mut fd_buf = [0; 1]; - let mut fd_len = 0; - match self { - &VmResponse::Ok => resp.type_ = Le32::from(VM_RESPONSE_TYPE_OK), - &VmResponse::Err(e) => { - resp.type_ = Le32::from(VM_RESPONSE_TYPE_ERR); - resp.errno = Le32::from(e.errno().checked_abs().unwrap_or(ERANGE) as u32); - } - &VmResponse::RegisterMemory { pfn, slot } => { - resp.type_ = Le32::from(VM_RESPONSE_TYPE_REGISTER_MEMORY); - resp.pfn = Le64::from(pfn); - resp.slot = Le32::from(slot); - } - &VmResponse::AllocateAndRegisterGpuMemory { - ref fd, - pfn, - slot, - desc, - } => { - fd_buf[0] = fd.as_raw_fd(); - fd_len = 1; - resp.type_ = Le32::from(VM_RESPONSE_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY); - resp.pfn = Le64::from(pfn); - resp.slot = Le32::from(slot); - resp.stride0 = Le32::from(desc.planes[0].stride); - resp.stride1 = Le32::from(desc.planes[1].stride); - resp.stride2 = Le32::from(desc.planes[2].stride); - resp.offset0 = Le32::from(desc.planes[0].offset); - resp.offset1 = Le32::from(desc.planes[1].offset); - resp.offset2 = Le32::from(desc.planes[2].offset); - } - } - let mut buf = [0; VM_RESPONSE_SIZE]; - buf.as_mut().get_ref(0).unwrap().store(resp); - s.send_with_fds(buf.as_ref(), &fd_buf[..fd_len]) - .map_err(|e| VmControlError::Send(e))?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use std::net::Shutdown; - - use sys_util::kernel_has_memfd; - use sys_util::SharedMemory; - - #[test] - fn request_exit() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - VmRequest::Exit.send(&s1).unwrap(); - match VmRequest::recv(&s2).unwrap() { - VmRequest::Exit => {} - _ => panic!("recv wrong request variant"), - } - } - - #[test] - fn request_register_memory() { - if !kernel_has_memfd() { - return; - } - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let shm_size: usize = 4096; - let mut shm = SharedMemory::new(None).unwrap(); - shm.set_size(shm_size as u64).unwrap(); - VmRequest::RegisterMemory(MaybeOwnedFd::Borrowed(shm.as_raw_fd()), shm_size) - .send(&s1) - .unwrap(); - match VmRequest::recv(&s2).unwrap() { - VmRequest::RegisterMemory(MaybeOwnedFd::Owned(fd), size) => { - assert!(fd.as_raw_fd() >= 0); - assert_eq!(size, shm_size); - } - _ => panic!("recv wrong request variant"), - } - } - - #[test] - fn request_unregister_memory() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - VmRequest::UnregisterMemory(77).send(&s1).unwrap(); - match VmRequest::recv(&s2).unwrap() { - VmRequest::UnregisterMemory(slot) => assert_eq!(slot, 77), - _ => panic!("recv wrong request variant"), - } - } - - #[test] - fn request_expect_fd() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let mut bad_request = [0; VM_REQUEST_SIZE]; - bad_request[0] = VM_REQUEST_TYPE_REGISTER_MEMORY as u8; - s2.send_with_fds(bad_request.as_ref(), &[]).unwrap(); - match VmRequest::recv(&s1) { - Err(VmControlError::ExpectFd) => {} - _ => panic!("recv wrong error variant"), - } - } - - #[test] - fn request_no_data() { - let (s1, _) = UnixDatagram::pair().expect("failed to create socket pair"); - s1.shutdown(Shutdown::Both).unwrap(); - match VmRequest::recv(&s1) { - Err(VmControlError::BadSize(s)) => assert_eq!(s, 0), - _ => panic!("recv wrong error variant"), - } - } - - #[test] - fn request_bad_size() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - s2.send_with_fds([12; 7].as_ref(), &[]).unwrap(); - match VmRequest::recv(&s1) { - Err(VmControlError::BadSize(_)) => {} - _ => panic!("recv wrong error variant"), - } - } - - #[test] - fn request_invalid_type() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - s2.send_with_fds([12; VM_REQUEST_SIZE].as_ref(), &[]) - .unwrap(); - match VmRequest::recv(&s1) { - Err(VmControlError::InvalidType) => {} - _ => panic!("recv wrong error variant"), - } - } - - #[test] - fn request_allocate_and_register_gpu_memory() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let gpu_width: u32 = 32; - let gpu_height: u32 = 32; - let gpu_format: u32 = 0x34325258; - let r = VmRequest::AllocateAndRegisterGpuMemory { - width: gpu_width, - height: gpu_height, - format: gpu_format, - }; - r.send(&s1).unwrap(); - match VmRequest::recv(&s2).unwrap() { - VmRequest::AllocateAndRegisterGpuMemory { - width, - height, - format, - } => { - assert_eq!(width, gpu_width); - assert_eq!(height, gpu_width); - assert_eq!(format, gpu_format); - } - _ => panic!("recv wrong request variant"), - } - } - - #[test] - fn resp_ok() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - VmResponse::Ok.send(&s1).unwrap(); - match VmResponse::recv(&s2).unwrap() { - VmResponse::Ok => {} - _ => panic!("recv wrong response variant"), - } - } - - #[test] - fn resp_err() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let r1 = VmResponse::Err(SysError::new(libc::EDESTADDRREQ)); - r1.send(&s1).unwrap(); - match VmResponse::recv(&s2).unwrap() { - VmResponse::Err(e) => { - assert_eq!(e, SysError::new(libc::EDESTADDRREQ)); - } - _ => panic!("recv wrong response variant"), - } - } - - #[test] - fn resp_memory() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let memory_pfn = 55; - let memory_slot = 66; - let r1 = VmResponse::RegisterMemory { - pfn: memory_pfn, - slot: memory_slot, - }; - r1.send(&s1).unwrap(); - match VmResponse::recv(&s2).unwrap() { - VmResponse::RegisterMemory { pfn, slot } => { - assert_eq!(pfn, memory_pfn); - assert_eq!(slot, memory_slot); - } - _ => panic!("recv wrong response variant"), - } - } - - #[test] - fn resp_no_data() { - let (s1, _) = UnixDatagram::pair().expect("failed to create socket pair"); - s1.shutdown(Shutdown::Both).unwrap(); - match VmResponse::recv(&s1) { - Err(e) => { - assert_eq!(e, VmControlError::BadSize(0)); - } - _ => panic!("recv wrong response"), - } - } - - #[test] - fn resp_bad_size() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - s2.send_with_fds([12; 7].as_ref(), &[]).unwrap(); - match VmResponse::recv(&s1) { - Err(e) => { - assert_eq!(e, VmControlError::BadSize(7)); - } - _ => panic!("recv wrong response"), - } - } - - #[test] - fn resp_invalid_type() { - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - s2.send_with_fds([12; VM_RESPONSE_SIZE].as_ref(), &[]) - .unwrap(); - match VmResponse::recv(&s1) { - Err(e) => { - assert_eq!(e, VmControlError::InvalidType); - } - _ => panic!("recv wrong response"), - } - } - - #[test] - fn resp_allocate_and_register_gpu_memory() { - if !kernel_has_memfd() { - return; - } - let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair"); - let shm_size: usize = 4096; - let mut shm = SharedMemory::new(None).unwrap(); - shm.set_size(shm_size as u64).unwrap(); - let memory_pfn = 55; - let memory_slot = 66; - let memory_planes = [ - GpuMemoryPlaneDesc { - stride: 32, - offset: 84, - }, - GpuMemoryPlaneDesc { - stride: 48, - offset: 96, - }, - GpuMemoryPlaneDesc { - stride: 64, - offset: 112, - }, - ]; - let r1 = VmResponse::AllocateAndRegisterGpuMemory { - fd: MaybeOwnedFd::Borrowed(shm.as_raw_fd()), - pfn: memory_pfn, - slot: memory_slot, - desc: GpuMemoryDesc { - planes: memory_planes, - }, - }; - r1.send(&s1).unwrap(); - match VmResponse::recv(&s2).unwrap() { - VmResponse::AllocateAndRegisterGpuMemory { - fd, - pfn, - slot, - desc, - } => { - assert!(fd.as_raw_fd() >= 0); - assert_eq!(pfn, memory_pfn); - assert_eq!(slot, memory_slot); - assert_eq!(desc.planes, memory_planes); - } - _ => panic!("recv wrong response variant"), - } - } -} -- cgit 1.4.1