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 <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2021-07-15 10:33:17 +02:00
parent e481f97550
commit d4316d0228
2 changed files with 18 additions and 7 deletions

View File

@ -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<ApiRequest>,
) -> 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<ApiRequest>,
_body: &Option<Body>,
_file: Option<File>,
) -> std::result::Result<Option<Body>, HttpError> {
Err(HttpError::BadRequest)
}

View File

@ -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<ApiRequest>,
body: &Option<Body>,
file: Option<File>,
) -> std::result::Result<Option<Body>, 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,