From f6f4c68fb4ec654fb4566a03b660420788eff54e Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Mon, 23 Mar 2020 16:21:58 +0000 Subject: [PATCH] vmm: Add "add-pmem" to the API Add the HTTP and internal API entry points for adding persistent memory at runtime. Signed-off-by: Rob Bradford --- vmm/src/api/http.rs | 5 ++-- vmm/src/api/http_endpoint.rs | 49 +++++++++++++++++++++++++++++++++--- vmm/src/api/mod.rs | 28 +++++++++++++++++++-- vmm/src/lib.rs | 22 +++++++++++++++- 4 files changed, 95 insertions(+), 9 deletions(-) diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index 0dfc560cf..a5277e4e2 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -4,8 +4,8 @@ // use crate::api::http_endpoint::{ - VmActionHandler, VmAddDevice, VmAddDisk, VmCreate, VmInfo, VmRemoveDevice, VmResize, VmmPing, - VmmShutdown, + VmActionHandler, VmAddDevice, VmAddDisk, VmAddPmem, VmCreate, VmInfo, VmRemoveDevice, VmResize, + VmmPing, VmmShutdown, }; use crate::api::{ApiRequest, VmAction}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; @@ -68,6 +68,7 @@ lazy_static! { r.routes.insert(endpoint!("/vm.add-device"), Box::new(VmAddDevice {})); r.routes.insert(endpoint!("/vm.remove-device"), Box::new(VmRemoveDevice {})); r.routes.insert(endpoint!("/vm.add-disk"), Box::new(VmAddDisk {})); + r.routes.insert(endpoint!("/vm.add-pmem"), Box::new(VmAddPmem {})); r }; diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs index 81c88ca6b..1468f90fc 100644 --- a/vmm/src/api/http_endpoint.rs +++ b/vmm/src/api/http_endpoint.rs @@ -5,10 +5,10 @@ use crate::api::http::EndpointHandler; use crate::api::{ - vm_add_device, vm_add_disk, vm_boot, vm_create, vm_delete, vm_info, vm_pause, vm_reboot, - vm_remove_device, vm_resize, vm_resume, vm_shutdown, vmm_ping, vmm_shutdown, ApiError, - ApiRequest, ApiResult, DeviceConfig, DiskConfig, VmAction, VmConfig, VmRemoveDeviceData, - VmResizeData, + vm_add_device, vm_add_disk, vm_add_pmem, vm_boot, vm_create, vm_delete, vm_info, vm_pause, + vm_reboot, vm_remove_device, vm_resize, vm_resume, vm_shutdown, vmm_ping, vmm_shutdown, + ApiError, ApiRequest, ApiResult, DeviceConfig, DiskConfig, PmemConfig, VmAction, VmConfig, + VmRemoveDeviceData, VmResizeData, }; use micro_http::{Body, Method, Request, Response, StatusCode, Version}; use serde_json::Error as SerdeError; @@ -63,6 +63,9 @@ pub enum HttpError { /// Could not add a disk to a VM VmAddDisk(ApiError), + + /// Could not add a pmem device to a VM + VmAddPmem(ApiError), } fn error_response(error: HttpError, status: StatusCode) -> Response { @@ -395,3 +398,41 @@ impl EndpointHandler for VmAddDisk { } } } + +// /api/v1/vm.add-pmem handler +pub struct VmAddPmem {} + +impl EndpointHandler for VmAddPmem { + fn handle_request( + &self, + req: &Request, + api_notifier: EventFd, + api_sender: Sender, + ) -> Response { + match req.method() { + Method::Put => { + match &req.body { + Some(body) => { + // Deserialize into a PmemConfig + let vm_add_pmem_data: PmemConfig = match serde_json::from_slice(body.raw()) + .map_err(HttpError::SerdeJsonDeserialize) + { + Ok(config) => config, + Err(e) => return error_response(e, StatusCode::BadRequest), + }; + + match vm_add_pmem(api_notifier, api_sender, Arc::new(vm_add_pmem_data)) + .map_err(HttpError::VmAddPmem) + { + Ok(_) => Response::new(Version::Http11, StatusCode::NoContent), + Err(e) => error_response(e, StatusCode::InternalServerError), + } + } + + None => Response::new(Version::Http11, StatusCode::BadRequest), + } + } + _ => Response::new(Version::Http11, StatusCode::BadRequest), + } + } +} diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs index 8166234d9..a40c08c92 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs @@ -36,7 +36,7 @@ pub use self::http::start_http_thread; pub mod http; pub mod http_endpoint; -use crate::config::{DeviceConfig, DiskConfig, VmConfig}; +use crate::config::{DeviceConfig, DiskConfig, PmemConfig, VmConfig}; use crate::vm::{Error as VmError, VmState}; use std::io; use std::sync::mpsc::{channel, RecvError, SendError, Sender}; @@ -112,8 +112,11 @@ pub enum ApiError { /// Cannot apply seccomp filter ApplySeccompFilter(seccomp::Error), - /// The device could not be added to the VM. + /// The disk could not be added to the VM. VmAddDisk(VmError), + + /// The pmem device could not be added to the VM. + VmAddPmem(VmError), } pub type ApiResult = std::result::Result; @@ -210,6 +213,9 @@ pub enum ApiRequest { /// Add a disk to the VM. VmAddDisk(Arc, Sender), + + /// Add a pmem device to the VM. + VmAddPmem(Arc, Sender), } pub fn vm_create( @@ -416,3 +422,21 @@ pub fn vm_add_disk( Ok(()) } + +pub fn vm_add_pmem( + api_evt: EventFd, + api_sender: Sender, + data: Arc, +) -> ApiResult<()> { + let (response_sender, response_receiver) = channel(); + + // Send the VM add-pmem request. + api_sender + .send(ApiRequest::VmAddPmem(data, response_sender)) + .map_err(ApiError::RequestSend)?; + api_evt.write(1).map_err(ApiError::EventFdWrite)?; + + response_receiver.recv().map_err(ApiError::ResponseRecv)??; + + Ok(()) +} diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 71482d4db..d3e935d57 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -16,7 +16,7 @@ extern crate tempfile; extern crate vmm_sys_util; use crate::api::{ApiError, ApiRequest, ApiResponse, ApiResponsePayload, VmInfo, VmmPingResponse}; -use crate::config::{DeviceConfig, DiskConfig, VmConfig}; +use crate::config::{DeviceConfig, DiskConfig, PmemConfig, VmConfig}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::vm::{Error as VmError, Vm, VmState}; use libc::EFD_NONBLOCK; @@ -428,6 +428,19 @@ impl Vmm { } } + fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> result::Result<(), VmError> { + if let Some(ref mut vm) = self.vm { + if let Err(e) = vm.add_pmem(pmem_cfg) { + error!("Error when adding new pmem device to the VM: {:?}", e); + Err(e) + } else { + Ok(()) + } + } else { + Err(VmError::VmNotRunning) + } + } + fn control_loop(&mut self, api_receiver: Arc>) -> Result<()> { const EPOLL_EVENTS_LEN: usize = 100; @@ -604,6 +617,13 @@ impl Vmm { .map(|_| ApiResponsePayload::Empty); sender.send(response).map_err(Error::ApiResponseSend)?; } + ApiRequest::VmAddPmem(add_pmem_data, sender) => { + let response = self + .vm_add_pmem(add_pmem_data.as_ref().clone()) + .map_err(ApiError::VmAddPmem) + .map(|_| ApiResponsePayload::Empty); + sender.send(response).map_err(Error::ApiResponseSend)?; + } } } }