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, 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 176 vm_action_put_handler_body!(VmAddDevice); 177 vm_action_put_handler_body!(AddDisk); 178 vm_action_put_handler_body!(VmAddFs); 179 vm_action_put_handler_body!(VmAddPmem); 180 vm_action_put_handler_body!(VmAddVdpa); 181 vm_action_put_handler_body!(VmAddVsock); 182 vm_action_put_handler_body!(VmAddUserDevice); 183 vm_action_put_handler_body!(VmRemoveDevice); 184 vm_action_put_handler_body!(VmResize); 185 vm_action_put_handler_body!(VmResizeZone); 186 vm_action_put_handler_body!(VmRestore); 187 vm_action_put_handler_body!(VmSnapshot); 188 vm_action_put_handler_body!(VmReceiveMigration); 189 vm_action_put_handler_body!(VmSendMigration); 190 191 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 192 vm_action_put_handler_body!(VmCoredump); 193 194 impl PutHandler for VmAddNet { 195 fn handle_request( 196 &'static self, 197 api_notifier: EventFd, 198 api_sender: Sender<ApiRequest>, 199 body: &Option<Body>, 200 mut files: Vec<File>, 201 ) -> std::result::Result<Option<Body>, HttpError> { 202 if let Some(body) = body { 203 let mut net_cfg: NetConfig = serde_json::from_slice(body.raw())?; 204 if net_cfg.fds.is_some() { 205 warn!("Ignoring FDs sent via the HTTP request body"); 206 net_cfg.fds = None; 207 } 208 if !files.is_empty() { 209 let fds = files.drain(..).map(|f| f.into_raw_fd()).collect(); 210 net_cfg.fds = Some(fds); 211 } 212 self.send(api_notifier, api_sender, net_cfg) 213 .map_err(HttpError::ApiError) 214 } else { 215 Err(HttpError::BadRequest) 216 } 217 } 218 } 219 220 impl GetHandler for VmAddNet {} 221 222 // Common handler for boot, shutdown and reboot 223 pub struct VmActionHandler { 224 action: &'static dyn HttpVmAction, 225 } 226 227 impl VmActionHandler { 228 pub fn new(action: &'static dyn HttpVmAction) -> Self { 229 VmActionHandler { action } 230 } 231 } 232 233 impl EndpointHandler for VmActionHandler { 234 fn put_handler( 235 &self, 236 api_notifier: EventFd, 237 api_sender: Sender<ApiRequest>, 238 body: &Option<Body>, 239 files: Vec<File>, 240 ) -> std::result::Result<Option<Body>, HttpError> { 241 PutHandler::handle_request(self.action, api_notifier, api_sender, body, files) 242 } 243 244 fn get_handler( 245 &self, 246 api_notifier: EventFd, 247 api_sender: Sender<ApiRequest>, 248 _body: &Option<Body>, 249 ) -> std::result::Result<Option<Body>, HttpError> { 250 GetHandler::handle_request(self.action, api_notifier, api_sender) 251 } 252 } 253 254 // /api/v1/vm.info handler 255 pub struct VmInfo {} 256 257 impl EndpointHandler for VmInfo { 258 fn handle_request( 259 &self, 260 req: &Request, 261 api_notifier: EventFd, 262 api_sender: Sender<ApiRequest>, 263 ) -> Response { 264 match req.method() { 265 Method::Get => match crate::api::VmInfo 266 .send(api_notifier, api_sender, ()) 267 .map_err(HttpError::ApiError) 268 { 269 Ok(info) => { 270 let mut response = Response::new(Version::Http11, StatusCode::OK); 271 let info_serialized = serde_json::to_string(&info).unwrap(); 272 273 response.set_body(Body::new(info_serialized)); 274 response 275 } 276 Err(e) => error_response(e, StatusCode::InternalServerError), 277 }, 278 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 279 } 280 } 281 } 282 283 // /api/v1/vmm.info handler 284 pub struct VmmPing {} 285 286 impl EndpointHandler for VmmPing { 287 fn handle_request( 288 &self, 289 req: &Request, 290 api_notifier: EventFd, 291 api_sender: Sender<ApiRequest>, 292 ) -> Response { 293 match req.method() { 294 Method::Get => match crate::api::VmmPing 295 .send(api_notifier, api_sender, ()) 296 .map_err(HttpError::ApiError) 297 { 298 Ok(pong) => { 299 let mut response = Response::new(Version::Http11, StatusCode::OK); 300 let info_serialized = serde_json::to_string(&pong).unwrap(); 301 302 response.set_body(Body::new(info_serialized)); 303 response 304 } 305 Err(e) => error_response(e, StatusCode::InternalServerError), 306 }, 307 308 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 309 } 310 } 311 } 312 313 // /api/v1/vmm.shutdown handler 314 pub struct VmmShutdown {} 315 316 impl EndpointHandler for VmmShutdown { 317 fn handle_request( 318 &self, 319 req: &Request, 320 api_notifier: EventFd, 321 api_sender: Sender<ApiRequest>, 322 ) -> Response { 323 match req.method() { 324 Method::Put => { 325 match crate::api::VmmShutdown 326 .send(api_notifier, api_sender, ()) 327 .map_err(HttpError::ApiError) 328 { 329 Ok(_) => Response::new(Version::Http11, StatusCode::OK), 330 Err(e) => error_response(e, StatusCode::InternalServerError), 331 } 332 } 333 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 334 } 335 } 336 } 337