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 std::fs::File; 8 use std::os::unix::io::IntoRawFd; 9 use std::sync::mpsc::Sender; 10 11 use micro_http::{Body, Method, Request, Response, StatusCode, Version}; 12 use vmm_sys_util::eventfd::EventFd; 13 14 use crate::api::http::{error_response, EndpointHandler, HttpError}; 15 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 16 use crate::api::VmCoredump; 17 use crate::api::{ 18 AddDisk, ApiAction, ApiRequest, NetConfig, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, 19 VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmConfig, VmCounters, VmDelete, VmNmi, VmPause, 20 VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone, VmRestore, 21 VmResume, VmSendMigration, VmShutdown, VmSnapshot, 22 }; 23 use crate::config::RestoreConfig; 24 25 // /api/v1/vm.create handler 26 pub struct VmCreate {} 27 28 impl EndpointHandler for VmCreate { 29 fn handle_request( 30 &self, 31 req: &Request, 32 api_notifier: EventFd, 33 api_sender: Sender<ApiRequest>, 34 ) -> Response { 35 match req.method() { 36 Method::Put => { 37 match &req.body { 38 Some(body) => { 39 // Deserialize into a VmConfig 40 let mut vm_config: Box<VmConfig> = match serde_json::from_slice(body.raw()) 41 .map_err(HttpError::SerdeJsonDeserialize) 42 { 43 Ok(config) => config, 44 Err(e) => return error_response(e, StatusCode::BadRequest), 45 }; 46 47 if let Some(ref mut nets) = vm_config.net { 48 if nets.iter().any(|net| net.fds.is_some()) { 49 warn!("Ignoring FDs sent via the HTTP request body"); 50 } 51 for net in nets { 52 net.fds = None; 53 } 54 } 55 56 match crate::api::VmCreate 57 .send(api_notifier, api_sender, vm_config) 58 .map_err(HttpError::ApiError) 59 { 60 Ok(_) => Response::new(Version::Http11, StatusCode::NoContent), 61 Err(e) => error_response(e, StatusCode::InternalServerError), 62 } 63 } 64 65 None => Response::new(Version::Http11, StatusCode::BadRequest), 66 } 67 } 68 69 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 70 } 71 } 72 } 73 74 pub trait GetHandler { 75 fn handle_request( 76 &'static self, 77 _api_notifier: EventFd, 78 _api_sender: Sender<ApiRequest>, 79 ) -> std::result::Result<Option<Body>, HttpError> { 80 Err(HttpError::BadRequest) 81 } 82 } 83 84 pub trait PutHandler { 85 fn handle_request( 86 &'static self, 87 _api_notifier: EventFd, 88 _api_sender: Sender<ApiRequest>, 89 _body: &Option<Body>, 90 _files: Vec<File>, 91 ) -> std::result::Result<Option<Body>, HttpError> { 92 Err(HttpError::BadRequest) 93 } 94 } 95 96 pub trait HttpVmAction: GetHandler + PutHandler + Sync {} 97 98 impl<T: GetHandler + PutHandler + Sync> HttpVmAction for T {} 99 100 macro_rules! vm_action_get_handler { 101 ($action:ty) => { 102 impl GetHandler for $action { 103 fn handle_request( 104 &'static self, 105 api_notifier: EventFd, 106 api_sender: Sender<ApiRequest>, 107 ) -> std::result::Result<Option<Body>, HttpError> { 108 self.send(api_notifier, api_sender, ()) 109 .map_err(HttpError::ApiError) 110 } 111 } 112 113 impl PutHandler for $action {} 114 }; 115 } 116 117 macro_rules! vm_action_put_handler { 118 ($action:ty) => { 119 impl PutHandler for $action { 120 fn handle_request( 121 &'static self, 122 api_notifier: EventFd, 123 api_sender: Sender<ApiRequest>, 124 body: &Option<Body>, 125 _files: Vec<File>, 126 ) -> std::result::Result<Option<Body>, HttpError> { 127 if body.is_some() { 128 Err(HttpError::BadRequest) 129 } else { 130 self.send(api_notifier, api_sender, ()) 131 .map_err(HttpError::ApiError) 132 } 133 } 134 } 135 136 impl GetHandler for $action {} 137 }; 138 } 139 140 macro_rules! vm_action_put_handler_body { 141 ($action:ty) => { 142 impl PutHandler for $action { 143 fn handle_request( 144 &'static self, 145 api_notifier: EventFd, 146 api_sender: Sender<ApiRequest>, 147 body: &Option<Body>, 148 _files: Vec<File>, 149 ) -> std::result::Result<Option<Body>, HttpError> { 150 if let Some(body) = body { 151 self.send( 152 api_notifier, 153 api_sender, 154 serde_json::from_slice(body.raw())?, 155 ) 156 .map_err(HttpError::ApiError) 157 } else { 158 Err(HttpError::BadRequest) 159 } 160 } 161 } 162 163 impl GetHandler for $action {} 164 }; 165 } 166 167 vm_action_get_handler!(VmCounters); 168 169 vm_action_put_handler!(VmBoot); 170 vm_action_put_handler!(VmDelete); 171 vm_action_put_handler!(VmShutdown); 172 vm_action_put_handler!(VmReboot); 173 vm_action_put_handler!(VmPause); 174 vm_action_put_handler!(VmResume); 175 vm_action_put_handler!(VmPowerButton); 176 vm_action_put_handler!(VmNmi); 177 178 vm_action_put_handler_body!(VmAddDevice); 179 vm_action_put_handler_body!(AddDisk); 180 vm_action_put_handler_body!(VmAddFs); 181 vm_action_put_handler_body!(VmAddPmem); 182 vm_action_put_handler_body!(VmAddVdpa); 183 vm_action_put_handler_body!(VmAddVsock); 184 vm_action_put_handler_body!(VmAddUserDevice); 185 vm_action_put_handler_body!(VmRemoveDevice); 186 vm_action_put_handler_body!(VmResize); 187 vm_action_put_handler_body!(VmResizeZone); 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 impl PutHandler for VmRestore { 224 fn handle_request( 225 &'static self, 226 api_notifier: EventFd, 227 api_sender: Sender<ApiRequest>, 228 body: &Option<Body>, 229 mut files: Vec<File>, 230 ) -> std::result::Result<Option<Body>, HttpError> { 231 if let Some(body) = body { 232 let mut restore_cfg: RestoreConfig = serde_json::from_slice(body.raw())?; 233 234 let mut fds = Vec::new(); 235 if !files.is_empty() { 236 fds = files.drain(..).map(|f| f.into_raw_fd()).collect(); 237 } 238 let expected_fds = match restore_cfg.net_fds { 239 Some(ref net_fds) => net_fds.iter().map(|net| net.num_fds).sum(), 240 None => 0, 241 }; 242 if fds.len() != expected_fds { 243 error!( 244 "Number of FDs expected: {}, but received: {}", 245 expected_fds, 246 fds.len() 247 ); 248 return Err(HttpError::BadRequest); 249 } 250 if let Some(ref mut nets) = restore_cfg.net_fds { 251 warn!("Ignoring FDs sent via the HTTP request body"); 252 let mut start_idx = 0; 253 for restored_net in nets.iter_mut() { 254 let end_idx = start_idx + restored_net.num_fds; 255 restored_net.fds = Some(fds[start_idx..end_idx].to_vec()); 256 start_idx = end_idx; 257 } 258 } 259 260 self.send(api_notifier, api_sender, restore_cfg) 261 .map_err(HttpError::ApiError) 262 } else { 263 Err(HttpError::BadRequest) 264 } 265 } 266 } 267 268 impl GetHandler for VmRestore {} 269 270 // Common handler for boot, shutdown and reboot 271 pub struct VmActionHandler { 272 action: &'static dyn HttpVmAction, 273 } 274 275 impl VmActionHandler { 276 pub fn new(action: &'static dyn HttpVmAction) -> Self { 277 VmActionHandler { action } 278 } 279 } 280 281 impl EndpointHandler for VmActionHandler { 282 fn put_handler( 283 &self, 284 api_notifier: EventFd, 285 api_sender: Sender<ApiRequest>, 286 body: &Option<Body>, 287 files: Vec<File>, 288 ) -> std::result::Result<Option<Body>, HttpError> { 289 PutHandler::handle_request(self.action, api_notifier, api_sender, body, files) 290 } 291 292 fn get_handler( 293 &self, 294 api_notifier: EventFd, 295 api_sender: Sender<ApiRequest>, 296 _body: &Option<Body>, 297 ) -> std::result::Result<Option<Body>, HttpError> { 298 GetHandler::handle_request(self.action, api_notifier, api_sender) 299 } 300 } 301 302 // /api/v1/vm.info handler 303 pub struct VmInfo {} 304 305 impl EndpointHandler for VmInfo { 306 fn handle_request( 307 &self, 308 req: &Request, 309 api_notifier: EventFd, 310 api_sender: Sender<ApiRequest>, 311 ) -> Response { 312 match req.method() { 313 Method::Get => match crate::api::VmInfo 314 .send(api_notifier, api_sender, ()) 315 .map_err(HttpError::ApiError) 316 { 317 Ok(info) => { 318 let mut response = Response::new(Version::Http11, StatusCode::OK); 319 let info_serialized = serde_json::to_string(&info).unwrap(); 320 321 response.set_body(Body::new(info_serialized)); 322 response 323 } 324 Err(e) => error_response(e, StatusCode::InternalServerError), 325 }, 326 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 327 } 328 } 329 } 330 331 // /api/v1/vmm.info handler 332 pub struct VmmPing {} 333 334 impl EndpointHandler for VmmPing { 335 fn handle_request( 336 &self, 337 req: &Request, 338 api_notifier: EventFd, 339 api_sender: Sender<ApiRequest>, 340 ) -> Response { 341 match req.method() { 342 Method::Get => match crate::api::VmmPing 343 .send(api_notifier, api_sender, ()) 344 .map_err(HttpError::ApiError) 345 { 346 Ok(pong) => { 347 let mut response = Response::new(Version::Http11, StatusCode::OK); 348 let info_serialized = serde_json::to_string(&pong).unwrap(); 349 350 response.set_body(Body::new(info_serialized)); 351 response 352 } 353 Err(e) => error_response(e, StatusCode::InternalServerError), 354 }, 355 356 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 357 } 358 } 359 } 360 361 // /api/v1/vmm.shutdown handler 362 pub struct VmmShutdown {} 363 364 impl EndpointHandler for VmmShutdown { 365 fn handle_request( 366 &self, 367 req: &Request, 368 api_notifier: EventFd, 369 api_sender: Sender<ApiRequest>, 370 ) -> Response { 371 match req.method() { 372 Method::Put => { 373 match crate::api::VmmShutdown 374 .send(api_notifier, api_sender, ()) 375 .map_err(HttpError::ApiError) 376 { 377 Ok(_) => Response::new(Version::Http11, StatusCode::OK), 378 Err(e) => error_response(e, StatusCode::InternalServerError), 379 } 380 } 381 _ => error_response(HttpError::BadRequest, StatusCode::BadRequest), 382 } 383 } 384 } 385