From bca8a19244106cb2f5e3e4b53328e5d73351466f Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Wed, 24 Jun 2020 11:20:13 +0100 Subject: [PATCH] vmm: Implement HTTP API for obtaining counters The counters are a hash of device name to hash of counter name to u64 value. Currently the API is only implemented with a stub that returns an empty set of counters. Signed-off-by: Rob Bradford --- vmm/src/api/http.rs | 4 ++++ vmm/src/api/http_endpoint.rs | 18 ++++++++++++++++-- vmm/src/api/mod.rs | 11 +++++++++++ vmm/src/lib.rs | 20 ++++++++++++++++++++ vmm/src/vm.rs | 7 ++++++- 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index 5e59b3525..85674e41f 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -94,6 +94,9 @@ pub enum HttpError { /// Could not add a vsock device to a VM VmAddVsock(ApiError), + + /// Could not get counters from VM + VmCounters(ApiError), } impl From for HttpError { @@ -193,6 +196,7 @@ lazy_static! { r.routes.insert(endpoint!("/vm.add-pmem"), Box::new(VmActionHandler::new(VmAction::AddPmem(Arc::default())))); r.routes.insert(endpoint!("/vm.add-vsock"), Box::new(VmActionHandler::new(VmAction::AddVsock(Arc::default())))); r.routes.insert(endpoint!("/vm.boot"), Box::new(VmActionHandler::new(VmAction::Boot))); + r.routes.insert(endpoint!("/vm.counters"), Box::new(VmActionHandler::new(VmAction::Counters))); r.routes.insert(endpoint!("/vm.create"), Box::new(VmCreate {})); r.routes.insert(endpoint!("/vm.delete"), Box::new(VmActionHandler::new(VmAction::Delete))); r.routes.insert(endpoint!("/vm.info"), Box::new(VmInfo {})); diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs index c964024ff..a172df260 100644 --- a/vmm/src/api/http_endpoint.rs +++ b/vmm/src/api/http_endpoint.rs @@ -6,8 +6,9 @@ use crate::api::http::{error_response, EndpointHandler, HttpError}; use crate::api::{ vm_add_device, vm_add_disk, vm_add_fs, vm_add_net, vm_add_pmem, vm_add_vsock, vm_boot, - vm_create, vm_delete, vm_info, vm_pause, vm_reboot, vm_remove_device, vm_resize, vm_restore, - vm_resume, vm_shutdown, vm_snapshot, vmm_ping, vmm_shutdown, ApiRequest, VmAction, VmConfig, + vm_counters, vm_create, vm_delete, vm_info, vm_pause, vm_reboot, vm_remove_device, vm_resize, + vm_restore, vm_resume, vm_shutdown, vm_snapshot, vmm_ping, vmm_shutdown, ApiRequest, VmAction, + VmConfig, }; use micro_http::{Body, Method, Request, Response, StatusCode, Version}; use std::sync::mpsc::Sender; @@ -159,6 +160,19 @@ impl EndpointHandler for VmActionHandler { } } } + + fn get_handler( + &self, + api_notifier: EventFd, + api_sender: Sender, + _body: &Option, + ) -> std::result::Result, HttpError> { + use VmAction::*; + match self.action { + Counters => vm_counters(api_notifier, api_sender).map_err(HttpError::VmCounters), + _ => Err(HttpError::BadRequest), + } + } } // /api/v1/vm.info handler diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs index d451871f2..f49bdf52b 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs @@ -214,6 +214,9 @@ pub enum ApiRequest { /// Resume a VM. VmResume(Sender), + /// Get counters for a VM. + VmCounters(Sender), + /// Shut the previously booted virtual machine down. /// If the VM was not previously booted or created, the VMM API server /// will send a VmShutdown error back. @@ -300,6 +303,9 @@ pub enum VmAction { /// Resume a VM Resume, + /// Return VM counters + Counters, + /// Add VFIO device AddDevice(Arc), @@ -346,6 +352,7 @@ fn vm_action( Reboot => ApiRequest::VmReboot(response_sender), Pause => ApiRequest::VmPause(response_sender), Resume => ApiRequest::VmResume(response_sender), + Counters => ApiRequest::VmCounters(response_sender), AddDevice(v) => ApiRequest::VmAddDevice(v, response_sender), AddDisk(v) => ApiRequest::VmAddDisk(v, response_sender), AddFs(v) => ApiRequest::VmAddFs(v, response_sender), @@ -395,6 +402,10 @@ pub fn vm_resume(api_evt: EventFd, api_sender: Sender) -> ApiResult< vm_action(api_evt, api_sender, VmAction::Resume) } +pub fn vm_counters(api_evt: EventFd, api_sender: Sender) -> ApiResult> { + vm_action(api_evt, api_sender, VmAction::Counters) +} + pub fn vm_snapshot( api_evt: EventFd, api_sender: Sender, diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 58d358d13..2eefe5ae8 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -587,6 +587,18 @@ impl Vmm { } } + fn vm_counters(&mut self) -> result::Result, VmError> { + if let Some(ref mut vm) = self.vm { + let info = vm.counters().map_err(|e| { + error!("Error when getting counters from the VM: {:?}", e); + e + })?; + serde_json::to_vec(&info).map_err(VmError::SerializeJson) + } else { + Err(VmError::VmNotRunning) + } + } + fn control_loop(&mut self, api_receiver: Arc>) -> Result<()> { const EPOLL_EVENTS_LEN: usize = 100; @@ -807,6 +819,14 @@ impl Vmm { .map(ApiResponsePayload::VmAction); sender.send(response).map_err(Error::ApiResponseSend)?; } + ApiRequest::VmCounters(sender) => { + let response = self + .vm_counters() + .map_err(ApiError::VmInfo) + .map(ApiResponsePayload::VmAction); + + sender.send(response).map_err(Error::ApiResponseSend)?; + } } } } diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index e10d8dbd4..ec1335ee3 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -44,8 +44,8 @@ use linux_loader::cmdline::Cmdline; #[cfg(target_arch = "x86_64")] use linux_loader::loader::elf::Error::InvalidElfMagicNumber; use linux_loader::loader::KernelLoader; - use signal_hook::{iterator::Signals, SIGINT, SIGTERM, SIGWINCH}; +use std::collections::HashMap; #[cfg(target_arch = "x86_64")] use std::convert::TryInto; use std::ffi::CString; @@ -53,6 +53,7 @@ use std::fs::{File, OpenOptions}; use std::io::{self, Write}; #[cfg(target_arch = "x86_64")] use std::io::{Seek, SeekFrom}; +use std::num::Wrapping; use std::ops::Deref; use std::path::PathBuf; use std::sync::{Arc, Mutex, RwLock}; @@ -992,6 +993,10 @@ impl Vm { Ok(pci_device_info) } + pub fn counters(&self) -> Result>>> { + Ok(HashMap::new()) + } + fn os_signal_handler(signals: Signals, console_input_clone: Arc, on_tty: bool) { for signal in signals.forever() { match signal {