From d4316d022874311cfe95c7ce79defd6e4d5aac51 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Thu, 15 Jul 2021 10:33:17 +0200 Subject: [PATCH] vmm: http: Allow file descriptor to be sent with add-net In order to let a separate process open a TAP device and pass the file descriptor through the control message mechanism, this patch adds the support for sending a file descriptor over to the Cloud Hypervisor process along with the add-net HTTP API command. The implementation uses the NetConfig structure mutably to update the list of fds with the one passed through control message. The list should always be empty prior to this, as it makes no sense to provide a list of fds once the Cloud Hypervisor process has already been started. It is important to note that reboot is supported since the file descriptor is duplicated upon receival, letting the VM only use the duplicated one. The original file descriptor is kept open in order to support a potential reboot. Fixes #2525 Signed-off-by: Sebastien Boeuf --- vmm/src/api/http.rs | 5 ++++- vmm/src/api/http_endpoint.rs | 20 ++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index a8501da39..78f06d888 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -11,6 +11,7 @@ use micro_http::{Body, HttpServer, MediaType, Method, Request, Response, StatusC use seccomp::{SeccompAction, SeccompFilter}; use serde_json::Error as SerdeError; use std::collections::HashMap; +use std::fs::File; use std::os::unix::io::{IntoRawFd, RawFd}; use std::os::unix::net::UnixListener; use std::path::PathBuf; @@ -141,8 +142,9 @@ pub trait EndpointHandler: Sync + Send { api_notifier: EventFd, api_sender: Sender, ) -> Response { + let file = req.file.as_ref().map(|f| f.try_clone().unwrap()); let res = match req.method() { - Method::Put => self.put_handler(api_notifier, api_sender, &req.body), + Method::Put => self.put_handler(api_notifier, api_sender, &req.body, file), Method::Get => self.get_handler(api_notifier, api_sender, &req.body), _ => return Response::new(Version::Http11, StatusCode::BadRequest), }; @@ -170,6 +172,7 @@ pub trait EndpointHandler: Sync + Send { _api_notifier: EventFd, _api_sender: Sender, _body: &Option, + _file: Option, ) -> std::result::Result, HttpError> { Err(HttpError::BadRequest) } diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs index 91bf48652..fb7f4fcb3 100644 --- a/vmm/src/api/http_endpoint.rs +++ b/vmm/src/api/http_endpoint.rs @@ -11,7 +11,10 @@ use crate::api::{ vm_send_migration, vm_shutdown, vm_snapshot, vmm_ping, vmm_shutdown, ApiRequest, VmAction, VmConfig, }; +use crate::config::NetConfig; use micro_http::{Body, Method, Request, Response, StatusCode, Version}; +use std::fs::File; +use std::os::unix::io::IntoRawFd; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; use vmm_sys_util::eventfd::EventFd; @@ -73,6 +76,7 @@ impl EndpointHandler for VmActionHandler { api_notifier: EventFd, api_sender: Sender, body: &Option, + file: Option, ) -> std::result::Result, HttpError> { use VmAction::*; if let Some(body) = body { @@ -105,12 +109,16 @@ impl EndpointHandler for VmActionHandler { ) .map_err(HttpError::VmAddPmem), - AddNet(_) => vm_add_net( - api_notifier, - api_sender, - Arc::new(serde_json::from_slice(body.raw())?), - ) - .map_err(HttpError::VmAddNet), + AddNet(_) => { + let mut net_cfg: NetConfig = serde_json::from_slice(body.raw())?; + // Update network config with optional file that might have + // been sent through control message. + if let Some(file) = file { + net_cfg.fds = Some(vec![file.into_raw_fd()]); + } + vm_add_net(api_notifier, api_sender, Arc::new(net_cfg)) + .map_err(HttpError::VmAddNet) + } AddVsock(_) => vm_add_vsock( api_notifier,