1 // Copyright © 2019 Intel Corporation 2 // Copyright 2024 Alyssa Ross <hi@alyssa.is> 3 // 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 7 use crate::api::http::{error_response, EndpointHandler, HttpError}; 8 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 9 use crate::api::VmCoredump; 10 use crate::api::{ 11 AddDisk, ApiAction, ApiRequest, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, VmAddUserDevice, 12 VmAddVdpa, VmAddVsock, VmBoot, VmConfig, VmCounters, VmDelete, VmNmi, VmPause, VmPowerButton, 13 VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone, VmRestore, VmResume, 14 VmSendMigration, VmShutdown, VmSnapshot, 15 }; 16 use crate::config::NetConfig; 17 use micro_http::{Body, Method, Request, Response, StatusCode, Version}; 18 use std::fs::File; 19 use std::os::unix::io::IntoRawFd; 20 use std::sync::mpsc::Sender; 21 use std::sync::{Arc, Mutex}; 22 use vmm_sys_util::eventfd::EventFd; 23 24 // /api/v1/vm.create handler 25 pub struct VmCreate {} 26 27 impl EndpointHandler for VmCreate { 28 fn handle_request( 29 &self, 30 req: &Request, 31 api_notifier: EventFd, 32 api_sender: Sender<ApiRequest>, 33 ) -> Response { 34 match req.method() { 35 Method::Put => { 36 match &req.body { 37 Some(body) => { 38 // Deserialize into a VmConfig 39 let mut vm_config: VmConfig = match serde_json::from_slice(body.raw()) 40 .map_err(HttpError::SerdeJsonDeserialize) 41 { 42 Ok(config) => config, 43 Err(e) => return error_response(e, StatusCode::BadRequest), 44 }; 45 46 if let Some(ref mut nets) = vm_config.net { 47 if nets.iter().any(|net| net.fds.is_some()) { 48 warn!("Ignoring FDs sent via the HTTP request body"); 49 } 50 for net in nets { 51 net.fds = None; 52 } 53 } 54 55 match crate::api::VmCreate 56 .send(api_notifier, api_sender, Arc::new(Mutex::new(vm_config))) 57 .map_err(HttpError::ApiError) 58 { 59 Ok(_) => Response::new(Version::Http11, StatusCode::NoContent), 60 Err(e) => error_response(e, StatusCode::InternalServerError), 61 } 62 } 63 64 None => Response::new(Version::Http11, StatusCode::BadRequest), 65 } 66 } 67 68 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 69 } 70 } 71 } 72 73 pub trait GetHandler { 74 fn handle_request( 75 &'static self, 76 _api_notifier: EventFd, 77 _api_sender: Sender<ApiRequest>, 78 ) -> std::result::Result<Option<Body>, HttpError> { 79 Err(HttpError::BadRequest) 80 } 81 } 82 83 pub trait PutHandler { 84 fn handle_request( 85 &'static self, 86 _api_notifier: EventFd, 87 _api_sender: Sender<ApiRequest>, 88 _body: &Option<Body>, 89 _files: Vec<File>, 90 ) -> std::result::Result<Option<Body>, HttpError> { 91 Err(HttpError::BadRequest) 92 } 93 } 94 95 pub trait HttpVmAction: GetHandler + PutHandler + Sync {} 96 97 impl<T: GetHandler + PutHandler + Sync> HttpVmAction for T {} 98 99 macro_rules! vm_action_get_handler { 100 ($action:ty) => { 101 impl GetHandler for $action { 102 fn handle_request( 103 &'static self, 104 api_notifier: EventFd, 105 api_sender: Sender<ApiRequest>, 106 ) -> std::result::Result<Option<Body>, HttpError> { 107 self.send(api_notifier, api_sender, ()) 108 .map_err(HttpError::ApiError) 109 } 110 } 111 112 impl PutHandler for $action {} 113 }; 114 } 115 116 macro_rules! vm_action_put_handler { 117 ($action:ty) => { 118 impl PutHandler for $action { 119 fn handle_request( 120 &'static self, 121 api_notifier: EventFd, 122 api_sender: Sender<ApiRequest>, 123 body: &Option<Body>, 124 _files: Vec<File>, 125 ) -> std::result::Result<Option<Body>, HttpError> { 126 if body.is_some() { 127 Err(HttpError::BadRequest) 128 } else { 129 self.send(api_notifier, api_sender, ()) 130 .map_err(HttpError::ApiError) 131 } 132 } 133 } 134 135 impl GetHandler for $action {} 136 }; 137 } 138 139 macro_rules! vm_action_put_handler_body { 140 ($action:ty) => { 141 impl PutHandler for $action { 142 fn handle_request( 143 &'static self, 144 api_notifier: EventFd, 145 api_sender: Sender<ApiRequest>, 146 body: &Option<Body>, 147 _files: Vec<File>, 148 ) -> std::result::Result<Option<Body>, HttpError> { 149 if let Some(body) = body { 150 self.send( 151 api_notifier, 152 api_sender, 153 serde_json::from_slice(body.raw())?, 154 ) 155 .map_err(HttpError::ApiError) 156 } else { 157 Err(HttpError::BadRequest) 158 } 159 } 160 } 161 162 impl GetHandler for $action {} 163 }; 164 } 165 166 vm_action_get_handler!(VmCounters); 167 168 vm_action_put_handler!(VmBoot); 169 vm_action_put_handler!(VmDelete); 170 vm_action_put_handler!(VmShutdown); 171 vm_action_put_handler!(VmReboot); 172 vm_action_put_handler!(VmPause); 173 vm_action_put_handler!(VmResume); 174 vm_action_put_handler!(VmPowerButton); 175 vm_action_put_handler!(VmNmi); 176 177 vm_action_put_handler_body!(VmAddDevice); 178 vm_action_put_handler_body!(AddDisk); 179 vm_action_put_handler_body!(VmAddFs); 180 vm_action_put_handler_body!(VmAddPmem); 181 vm_action_put_handler_body!(VmAddVdpa); 182 vm_action_put_handler_body!(VmAddVsock); 183 vm_action_put_handler_body!(VmAddUserDevice); 184 vm_action_put_handler_body!(VmRemoveDevice); 185 vm_action_put_handler_body!(VmResize); 186 vm_action_put_handler_body!(VmResizeZone); 187 vm_action_put_handler_body!(VmRestore); 188 vm_action_put_handler_body!(VmSnapshot); 189 vm_action_put_handler_body!(VmReceiveMigration); 190 vm_action_put_handler_body!(VmSendMigration); 191 192 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 193 vm_action_put_handler_body!(VmCoredump); 194 195 impl PutHandler for VmAddNet { 196 fn handle_request( 197 &'static self, 198 api_notifier: EventFd, 199 api_sender: Sender<ApiRequest>, 200 body: &Option<Body>, 201 mut files: Vec<File>, 202 ) -> std::result::Result<Option<Body>, HttpError> { 203 if let Some(body) = body { 204 let mut net_cfg: NetConfig = serde_json::from_slice(body.raw())?; 205 if net_cfg.fds.is_some() { 206 warn!("Ignoring FDs sent via the HTTP request body"); 207 net_cfg.fds = None; 208 } 209 if !files.is_empty() { 210 let fds = files.drain(..).map(|f| f.into_raw_fd()).collect(); 211 net_cfg.fds = Some(fds); 212 } 213 self.send(api_notifier, api_sender, net_cfg) 214 .map_err(HttpError::ApiError) 215 } else { 216 Err(HttpError::BadRequest) 217 } 218 } 219 } 220 221 impl GetHandler for VmAddNet {} 222 223 // Common handler for boot, shutdown and reboot 224 pub struct VmActionHandler { 225 action: &'static dyn HttpVmAction, 226 } 227 228 impl VmActionHandler { 229 pub fn new(action: &'static dyn HttpVmAction) -> Self { 230 VmActionHandler { action } 231 } 232 } 233 234 impl EndpointHandler for VmActionHandler { 235 fn put_handler( 236 &self, 237 api_notifier: EventFd, 238 api_sender: Sender<ApiRequest>, 239 body: &Option<Body>, 240 files: Vec<File>, 241 ) -> std::result::Result<Option<Body>, HttpError> { 242 PutHandler::handle_request(self.action, api_notifier, api_sender, body, files) 243 } 244 245 fn get_handler( 246 &self, 247 api_notifier: EventFd, 248 api_sender: Sender<ApiRequest>, 249 _body: &Option<Body>, 250 ) -> std::result::Result<Option<Body>, HttpError> { 251 GetHandler::handle_request(self.action, api_notifier, api_sender) 252 } 253 } 254 255 // /api/v1/vm.info handler 256 pub struct VmInfo {} 257 258 impl EndpointHandler for VmInfo { 259 fn handle_request( 260 &self, 261 req: &Request, 262 api_notifier: EventFd, 263 api_sender: Sender<ApiRequest>, 264 ) -> Response { 265 match req.method() { 266 Method::Get => match crate::api::VmInfo 267 .send(api_notifier, api_sender, ()) 268 .map_err(HttpError::ApiError) 269 { 270 Ok(info) => { 271 let mut response = Response::new(Version::Http11, StatusCode::OK); 272 let info_serialized = serde_json::to_string(&info).unwrap(); 273 274 response.set_body(Body::new(info_serialized)); 275 response 276 } 277 Err(e) => error_response(e, StatusCode::InternalServerError), 278 }, 279 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 280 } 281 } 282 } 283 284 // /api/v1/vmm.info handler 285 pub struct VmmPing {} 286 287 impl EndpointHandler for VmmPing { 288 fn handle_request( 289 &self, 290 req: &Request, 291 api_notifier: EventFd, 292 api_sender: Sender<ApiRequest>, 293 ) -> Response { 294 match req.method() { 295 Method::Get => match crate::api::VmmPing 296 .send(api_notifier, api_sender, ()) 297 .map_err(HttpError::ApiError) 298 { 299 Ok(pong) => { 300 let mut response = Response::new(Version::Http11, StatusCode::OK); 301 let info_serialized = serde_json::to_string(&pong).unwrap(); 302 303 response.set_body(Body::new(info_serialized)); 304 response 305 } 306 Err(e) => error_response(e, StatusCode::InternalServerError), 307 }, 308 309 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 310 } 311 } 312 } 313 314 // /api/v1/vmm.shutdown handler 315 pub struct VmmShutdown {} 316 317 impl EndpointHandler for VmmShutdown { 318 fn handle_request( 319 &self, 320 req: &Request, 321 api_notifier: EventFd, 322 api_sender: Sender<ApiRequest>, 323 ) -> Response { 324 match req.method() { 325 Method::Put => { 326 match crate::api::VmmShutdown 327 .send(api_notifier, api_sender, ()) 328 .map_err(HttpError::ApiError) 329 { 330 Ok(_) => Response::new(Version::Http11, StatusCode::OK), 331 Err(e) => error_response(e, StatusCode::InternalServerError), 332 } 333 } 334 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 335 } 336 } 337 } 338