vmm: api: Support multiple fds with add-net

Based on the latest code from the micro-http crate, this patch adds the
support for multiple file descriptors to be sent along with the add-net
request. This means we can now hotplug multiqueue network interface to
the VM.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2022-01-21 08:54:22 +01:00 committed by Rob Bradford
parent 400c28fa58
commit 4e46a1bc3c
3 changed files with 13 additions and 8 deletions

2
Cargo.lock generated
View File

@ -493,7 +493,7 @@ dependencies = [
[[package]] [[package]]
name = "micro_http" name = "micro_http"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#0a58eb1ece68e326e68365c4297d0a7c08ecd9bc" source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#a730d86940081ad044cdfbc1285c1db6d3048392"
dependencies = [ dependencies = [
"libc", "libc",
"vmm-sys-util", "vmm-sys-util",

View File

@ -146,9 +146,13 @@ pub trait EndpointHandler: Sync + Send {
api_notifier: EventFd, api_notifier: EventFd,
api_sender: Sender<ApiRequest>, api_sender: Sender<ApiRequest>,
) -> Response { ) -> Response {
let file = req.file.as_ref().map(|f| f.try_clone().unwrap()); // Cloning the files here is very important as it dup() the file
// descriptors, leaving open the one that was received. This way,
// rebooting the VM will work since the VM will be created from the
// original file descriptors.
let files = req.files.iter().map(|f| f.try_clone().unwrap()).collect();
let res = match req.method() { let res = match req.method() {
Method::Put => self.put_handler(api_notifier, api_sender, &req.body, file), Method::Put => self.put_handler(api_notifier, api_sender, &req.body, files),
Method::Get => self.get_handler(api_notifier, api_sender, &req.body), Method::Get => self.get_handler(api_notifier, api_sender, &req.body),
_ => return Response::new(Version::Http11, StatusCode::BadRequest), _ => return Response::new(Version::Http11, StatusCode::BadRequest),
}; };
@ -176,7 +180,7 @@ pub trait EndpointHandler: Sync + Send {
_api_notifier: EventFd, _api_notifier: EventFd,
_api_sender: Sender<ApiRequest>, _api_sender: Sender<ApiRequest>,
_body: &Option<Body>, _body: &Option<Body>,
_file: Option<File>, _files: Vec<File>,
) -> std::result::Result<Option<Body>, HttpError> { ) -> std::result::Result<Option<Body>, HttpError> {
Err(HttpError::BadRequest) Err(HttpError::BadRequest)
} }

View File

@ -76,7 +76,7 @@ impl EndpointHandler for VmActionHandler {
api_notifier: EventFd, api_notifier: EventFd,
api_sender: Sender<ApiRequest>, api_sender: Sender<ApiRequest>,
body: &Option<Body>, body: &Option<Body>,
file: Option<File>, mut files: Vec<File>,
) -> std::result::Result<Option<Body>, HttpError> { ) -> std::result::Result<Option<Body>, HttpError> {
use VmAction::*; use VmAction::*;
if let Some(body) = body { if let Some(body) = body {
@ -111,10 +111,11 @@ impl EndpointHandler for VmActionHandler {
AddNet(_) => { AddNet(_) => {
let mut net_cfg: NetConfig = serde_json::from_slice(body.raw())?; let mut net_cfg: NetConfig = serde_json::from_slice(body.raw())?;
// Update network config with optional file that might have // Update network config with optional files that might have
// been sent through control message. // been sent through control message.
if let Some(file) = file { if !files.is_empty() {
net_cfg.fds = Some(vec![file.into_raw_fd()]); let fds = files.drain(..).map(|f| f.into_raw_fd()).collect();
net_cfg.fds = Some(fds);
} }
vm_add_net(api_notifier, api_sender, Arc::new(net_cfg)) vm_add_net(api_notifier, api_sender, Arc::new(net_cfg))
.map_err(HttpError::VmAddNet) .map_err(HttpError::VmAddNet)