2019-02-22 16:04:35 +00:00
|
|
|
// Copyright © 2019 Intel Corporation
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
//
|
|
|
|
|
2019-05-19 02:24:47 +00:00
|
|
|
#[macro_use]
|
|
|
|
extern crate log;
|
2019-09-25 12:09:33 +00:00
|
|
|
extern crate vmm_sys_util;
|
2019-02-22 16:04:35 +00:00
|
|
|
|
2019-09-25 12:09:33 +00:00
|
|
|
use libc::EFD_NONBLOCK;
|
2019-05-10 08:46:27 +00:00
|
|
|
use std::fmt::{self, Display};
|
2019-09-25 12:09:33 +00:00
|
|
|
use std::io;
|
2019-09-25 12:25:08 +00:00
|
|
|
use std::os::unix::io::{AsRawFd, RawFd};
|
2019-05-10 08:46:27 +00:00
|
|
|
use std::result;
|
2019-09-24 14:00:00 +00:00
|
|
|
use std::sync::Arc;
|
2019-09-25 12:09:33 +00:00
|
|
|
use vmm_sys_util::eventfd::EventFd;
|
2019-03-07 13:56:43 +00:00
|
|
|
|
2019-09-25 12:14:15 +00:00
|
|
|
pub mod api;
|
2019-05-23 19:48:05 +00:00
|
|
|
pub mod config;
|
2019-09-04 13:55:14 +00:00
|
|
|
pub mod device_manager;
|
2019-02-28 13:16:58 +00:00
|
|
|
pub mod vm;
|
2019-02-22 16:04:35 +00:00
|
|
|
|
2019-05-23 19:48:05 +00:00
|
|
|
use self::config::VmConfig;
|
2019-08-29 13:51:45 +00:00
|
|
|
use self::vm::{ExitBehaviour, Vm};
|
2019-05-10 08:46:27 +00:00
|
|
|
|
|
|
|
/// Errors associated with VM management
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
2019-09-25 12:09:33 +00:00
|
|
|
/// Cannot create EventFd.
|
|
|
|
EventFd(io::Error),
|
|
|
|
|
2019-05-10 08:46:27 +00:00
|
|
|
/// Cannot create a new VM.
|
|
|
|
VmNew(vm::Error),
|
|
|
|
|
|
|
|
/// Cannot start a VM.
|
|
|
|
VmStart(vm::Error),
|
2019-09-24 14:14:04 +00:00
|
|
|
|
|
|
|
/// Cannot stop a VM.
|
|
|
|
VmStop(vm::Error),
|
2019-05-10 08:46:27 +00:00
|
|
|
}
|
|
|
|
pub type Result<T> = result::Result<T, Error>;
|
|
|
|
|
|
|
|
impl Display for Error {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
use self::Error::*;
|
|
|
|
|
|
|
|
match self {
|
2019-09-25 12:09:33 +00:00
|
|
|
EventFd(e) => write!(f, "Can not create EventFd: {:?}", e),
|
2019-05-10 08:46:27 +00:00
|
|
|
VmNew(e) => write!(f, "Can not create a new virtual machine: {:?}", e),
|
|
|
|
VmStart(e) => write!(f, "Can not start a new virtual machine: {:?}", e),
|
2019-09-24 14:14:04 +00:00
|
|
|
VmStop(e) => write!(f, "Can not stop a virtual machine: {:?}", e),
|
2019-05-10 08:46:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-22 16:04:35 +00:00
|
|
|
|
2019-09-25 12:25:08 +00:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
pub enum EpollDispatch {
|
|
|
|
Exit,
|
|
|
|
Reset,
|
|
|
|
Stdin,
|
|
|
|
Api,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct EpollContext {
|
|
|
|
raw_fd: RawFd,
|
|
|
|
dispatch_table: Vec<Option<EpollDispatch>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EpollContext {
|
|
|
|
pub fn new() -> result::Result<EpollContext, io::Error> {
|
|
|
|
let raw_fd = epoll::create(true)?;
|
|
|
|
|
|
|
|
// Initial capacity needs to be large enough to hold:
|
|
|
|
// * 1 exit event
|
|
|
|
// * 1 reset event
|
|
|
|
// * 1 stdin event
|
|
|
|
// * 1 API event
|
|
|
|
let mut dispatch_table = Vec::with_capacity(5);
|
|
|
|
dispatch_table.push(None);
|
|
|
|
|
|
|
|
Ok(EpollContext {
|
|
|
|
raw_fd,
|
|
|
|
dispatch_table,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_stdin(&mut self) -> result::Result<(), io::Error> {
|
|
|
|
let dispatch_index = self.dispatch_table.len() as u64;
|
|
|
|
epoll::ctl(
|
|
|
|
self.raw_fd,
|
|
|
|
epoll::ControlOptions::EPOLL_CTL_ADD,
|
|
|
|
libc::STDIN_FILENO,
|
|
|
|
epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
self.dispatch_table.push(Some(EpollDispatch::Stdin));
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_event<T>(&mut self, fd: &T, token: EpollDispatch) -> result::Result<(), io::Error>
|
|
|
|
where
|
|
|
|
T: AsRawFd,
|
|
|
|
{
|
|
|
|
let dispatch_index = self.dispatch_table.len() as u64;
|
|
|
|
epoll::ctl(
|
|
|
|
self.raw_fd,
|
|
|
|
epoll::ControlOptions::EPOLL_CTL_ADD,
|
|
|
|
fd.as_raw_fd(),
|
|
|
|
epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
|
|
|
|
)?;
|
|
|
|
self.dispatch_table.push(Some(token));
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRawFd for EpollContext {
|
|
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
|
|
self.raw_fd
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-24 14:00:00 +00:00
|
|
|
pub fn start_vm_loop(config: Arc<VmConfig>) -> Result<()> {
|
2019-09-25 12:09:33 +00:00
|
|
|
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFd)?;
|
|
|
|
let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFd)?;
|
|
|
|
|
2019-08-29 13:51:45 +00:00
|
|
|
loop {
|
2019-09-25 12:09:33 +00:00
|
|
|
let mut vm = Vm::new(
|
|
|
|
config.clone(),
|
|
|
|
exit_evt.try_clone().unwrap(),
|
|
|
|
reset_evt.try_clone().unwrap(),
|
|
|
|
)
|
|
|
|
.map_err(Error::VmNew)?;
|
2019-02-22 16:04:35 +00:00
|
|
|
|
2019-09-23 23:03:05 +00:00
|
|
|
if vm.start().map_err(Error::VmStart)? == ExitBehaviour::Shutdown {
|
2019-09-24 14:14:04 +00:00
|
|
|
vm.stop().map_err(Error::VmStop)?;
|
2019-08-29 13:51:45 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-09-06 17:37:41 +00:00
|
|
|
|
2019-09-24 14:14:04 +00:00
|
|
|
vm.stop().map_err(Error::VmStop)?;
|
|
|
|
|
2019-09-06 17:37:41 +00:00
|
|
|
#[cfg(not(feature = "acpi"))]
|
|
|
|
break;
|
2019-08-29 13:51:45 +00:00
|
|
|
}
|
2019-02-22 16:04:35 +00:00
|
|
|
|
2019-02-28 13:16:58 +00:00
|
|
|
Ok(())
|
2019-02-22 16:04:35 +00:00
|
|
|
}
|