diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index a5277e4e2..9b3ccd462 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, VmAddPmem, VmCreate, VmInfo, VmRemoveDevice, VmResize, - VmmPing, VmmShutdown, + VmActionHandler, VmAddDevice, VmAddDisk, VmAddNet, VmAddPmem, VmCreate, VmInfo, VmRemoveDevice, + VmResize, VmmPing, VmmShutdown, }; use crate::api::{ApiRequest, VmAction}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; @@ -69,6 +69,7 @@ lazy_static! { 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.routes.insert(endpoint!("/vm.add-net"), Box::new(VmAddNet {})); r }; diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs index 1468f90fc..5738fbcd1 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_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, + vm_add_device, vm_add_disk, vm_add_net, 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, NetConfig, PmemConfig, + VmAction, VmConfig, VmRemoveDeviceData, VmResizeData, }; use micro_http::{Body, Method, Request, Response, StatusCode, Version}; use serde_json::Error as SerdeError; @@ -66,6 +66,9 @@ pub enum HttpError { /// Could not add a pmem device to a VM VmAddPmem(ApiError), + + /// Could not add a network device to a VM + VmAddNet(ApiError), } fn error_response(error: HttpError, status: StatusCode) -> Response { @@ -436,3 +439,41 @@ impl EndpointHandler for VmAddPmem { } } } + +// /api/v1/vm.add-net handler +pub struct VmAddNet {} + +impl EndpointHandler for VmAddNet { + 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 NetConfig + let vm_add_net_data: NetConfig = 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_net(api_notifier, api_sender, Arc::new(vm_add_net_data)) + .map_err(HttpError::VmAddNet) + { + 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 a40c08c92..876491919 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, PmemConfig, VmConfig}; +use crate::config::{DeviceConfig, DiskConfig, NetConfig, PmemConfig, VmConfig}; use crate::vm::{Error as VmError, VmState}; use std::io; use std::sync::mpsc::{channel, RecvError, SendError, Sender}; @@ -117,6 +117,9 @@ pub enum ApiError { /// The pmem device could not be added to the VM. VmAddPmem(VmError), + + /// The network device could not be added to the VM. + VmAddNet(VmError), } pub type ApiResult = std::result::Result; @@ -216,6 +219,9 @@ pub enum ApiRequest { /// Add a pmem device to the VM. VmAddPmem(Arc, Sender), + + /// Add a network device to the VM. + VmAddNet(Arc, Sender), } pub fn vm_create( @@ -440,3 +446,21 @@ pub fn vm_add_pmem( Ok(()) } + +pub fn vm_add_net( + api_evt: EventFd, + api_sender: Sender, + data: Arc, +) -> ApiResult<()> { + let (response_sender, response_receiver) = channel(); + + // Send the VM add-net request. + api_sender + .send(ApiRequest::VmAddNet(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 d3e935d57..49ed0cdee 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, PmemConfig, VmConfig}; +use crate::config::{DeviceConfig, DiskConfig, NetConfig, PmemConfig, VmConfig}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::vm::{Error as VmError, Vm, VmState}; use libc::EFD_NONBLOCK; @@ -441,6 +441,19 @@ impl Vmm { } } + fn vm_add_net(&mut self, net_cfg: NetConfig) -> result::Result<(), VmError> { + if let Some(ref mut vm) = self.vm { + if let Err(e) = vm.add_net(net_cfg) { + error!("Error when adding new network 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; @@ -624,6 +637,13 @@ impl Vmm { .map(|_| ApiResponsePayload::Empty); sender.send(response).map_err(Error::ApiResponseSend)?; } + ApiRequest::VmAddNet(add_net_data, sender) => { + let response = self + .vm_add_net(add_net_data.as_ref().clone()) + .map_err(ApiError::VmAddNet) + .map(|_| ApiResponsePayload::Empty); + sender.send(response).map_err(Error::ApiResponseSend)?; + } } } }