vmm: add endpoint api for NMI support

Add http endpoint for trigger nmi.

Signed-off-by: Yi Wang <foxywang@tencent.com>
This commit is contained in:
Yi Wang 2023-11-26 18:59:54 +08:00 committed by Rob Bradford
parent f8ac38d113
commit f40dd4a993
5 changed files with 58 additions and 2 deletions

View File

@ -273,6 +273,10 @@ impl RequestHandler for StubApiRequestHandler {
fn vm_send_migration(&mut self, _: VmSendMigrationData) -> Result<(), MigratableError> {
Ok(())
}
fn vm_nmi(&mut self) -> Result<(), VmError> {
Ok(())
}
}
fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) {

View File

@ -9,7 +9,7 @@ use crate::api::http::{error_response, EndpointHandler, HttpError};
use crate::api::VmCoredump;
use crate::api::{
AddDisk, ApiAction, ApiRequest, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, VmAddUserDevice,
VmAddVdpa, VmAddVsock, VmBoot, VmConfig, VmCounters, VmDelete, VmPause, VmPowerButton,
VmAddVdpa, VmAddVsock, VmBoot, VmConfig, VmCounters, VmDelete, VmNmi, VmPause, VmPowerButton,
VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone, VmRestore, VmResume,
VmSendMigration, VmShutdown, VmSnapshot,
};
@ -172,6 +172,7 @@ vm_action_put_handler!(VmReboot);
vm_action_put_handler!(VmPause);
vm_action_put_handler!(VmResume);
vm_action_put_handler!(VmPowerButton);
vm_action_put_handler!(VmNmi);
vm_action_put_handler_body!(VmAddDevice);
vm_action_put_handler_body!(AddDisk);

View File

@ -8,7 +8,7 @@ use self::http_endpoint::{VmActionHandler, VmCreate, VmInfo, VmmPing, VmmShutdow
use crate::api::VmCoredump;
use crate::api::{
AddDisk, ApiError, ApiRequest, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, VmAddUserDevice,
VmAddVdpa, VmAddVsock, VmBoot, VmCounters, VmDelete, VmPause, VmPowerButton, VmReboot,
VmAddVdpa, VmAddVsock, VmBoot, VmCounters, VmDelete, VmNmi, VmPause, VmPowerButton, VmReboot,
VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone, VmRestore, VmResume,
VmSendMigration, VmShutdown, VmSnapshot,
};
@ -268,6 +268,8 @@ pub static HTTP_ROUTES: Lazy<HttpRoutes> = Lazy::new(|| {
.insert(endpoint!("/vmm.ping"), Box::new(VmmPing {}));
r.routes
.insert(endpoint!("/vmm.shutdown"), Box::new(VmmShutdown {}));
r.routes
.insert(endpoint!("/vm.nmi"), Box::new(VmActionHandler::new(&VmNmi)));
r
});

View File

@ -159,6 +159,9 @@ pub enum ApiError {
/// Error triggering power button
VmPowerButton(VmError),
/// Error triggering NMI
VmNmi(VmError),
}
pub type ApiResult<T> = Result<T, ApiError>;
@ -200,6 +203,7 @@ impl Display for ApiError {
VmReceiveMigration(migratable_error) => write!(f, "{}", migratable_error),
VmSendMigration(migratable_error) => write!(f, "{}", migratable_error),
VmPowerButton(vm_error) => write!(f, "{}", vm_error),
VmNmi(vm_error) => write!(f, "{}", vm_error),
}
}
}
@ -353,6 +357,8 @@ pub trait RequestHandler {
&mut self,
send_data_migration: VmSendMigrationData,
) -> Result<(), MigratableError>;
fn vm_nmi(&mut self) -> Result<(), VmError>;
}
/// It would be nice if we could pass around an object like this:
@ -380,6 +386,7 @@ fn get_response<Action: ApiAction>(
let (response_sender, response_receiver) = channel();
let request = action.request(data, response_sender);
// Send the VM request.
api_sender.send(request).map_err(ApiError::RequestSend)?;
api_evt.write(1).map_err(ApiError::EventFdWrite)?;
@ -1415,3 +1422,36 @@ impl ApiAction for VmmShutdown {
Ok(())
}
}
pub struct VmNmi;
impl ApiAction for VmNmi {
type RequestBody = ();
type ResponseBody = Option<Body>;
fn request(&self, _: Self::RequestBody, response_sender: Sender<ApiResponse>) -> ApiRequest {
Box::new(move |vmm| {
info!("API request event: VmNmi");
let response = vmm
.vm_nmi()
.map_err(ApiError::VmNmi)
.map(|_| ApiResponsePayload::Empty);
response_sender
.send(response)
.map_err(VmmError::ApiResponseSend)?;
Ok(false)
})
}
fn send(
&self,
api_evt: EventFd,
api_sender: Sender<ApiRequest>,
data: Self::RequestBody,
) -> ApiResult<Self::ResponseBody> {
get_response_body(self, api_evt, api_sender, data)
}
}

View File

@ -1840,6 +1840,15 @@ impl RequestHandler for Vmm {
}
}
fn vm_nmi(&mut self) -> result::Result<(), VmError> {
if let Some(ref mut vm) = self.vm {
info!("nmi");
vm.power_button()
} else {
Err(VmError::VmNotRunning)
}
}
fn vm_receive_migration(
&mut self,
receive_data_migration: VmReceiveMigrationData,