1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
lib.rs 49 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
yexiao Отправлено 3 лет назад 84f250f
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391
// Copyright (c) 2020 Huawei Technologies Co.,Ltd. All rights reserved.
//
// StratoVirt is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
pub mod errors {
use error_chain::error_chain;
error_chain! {
links {
AddressSpace(address_space::errors::Error, address_space::errors::ErrorKind);
IntCtrl(devices::IntCtrlErrs::Error, devices::IntCtrlErrs::ErrorKind) #[cfg(target_arch = "aarch64")];
Legacy(devices::LegacyErrs::Error, devices::LegacyErrs::ErrorKind);
MicroVm(super::micro_vm::errors::Error, super::micro_vm::errors::ErrorKind);
StdVm(super::standard_vm::errors::Error, super::standard_vm::errors::ErrorKind);
Util(util::errors::Error, util::errors::ErrorKind);
Virtio(virtio::errors::Error, virtio::errors::ErrorKind);
MachineManager(machine_manager::config::errors::Error, machine_manager::config::errors::ErrorKind);
Hypervisor(hypervisor::errors::Error, hypervisor::errors::ErrorKind);
}
foreign_links {
KvmIoctl(kvm_ioctls::Error);
Io(std::io::Error);
}
errors {
AddDevErr(dev: String) {
display("Failed to add {} device.", dev)
}
LoadKernErr {
display("Failed to load kernel.")
}
CrtMemSpaceErr {
display("Failed to create memory address space")
}
CrtIoSpaceErr {
display("Failed to create I/O address space")
}
RegMemRegionErr(base: u64, size: u64) {
display("Failed to register region in memory space: base={},size={}", base, size)
}
InitEventFdErr(fd: String) {
display("Failed to init eventfd {}.", fd)
}
RlzVirtioMmioErr {
display("Failed to realize virtio mmio.")
}
#[cfg(target_arch = "x86_64")]
CrtIrqchipErr {
display("Failed to create irq chip.")
}
#[cfg(target_arch = "x86_64")]
SetTssErr {
display("Failed to set tss address.")
}
#[cfg(target_arch = "x86_64")]
CrtPitErr {
display("Failed to create PIT.")
}
#[cfg(target_arch = "aarch64")]
GenFdtErr {
display("Failed to generate FDT.")
}
#[cfg(target_arch = "aarch64")]
WrtFdtErr(addr: u64, size: usize) {
display("Failed to write FDT: addr={}, size={}", addr, size)
}
RegNotifierErr {
display("Failed to register event notifier.")
}
StartVcpuErr(id: u8) {
display("Failed to run vcpu{}.", id)
}
PauseVcpuErr(id: u8) {
display("Failed to pause vcpu{}.", id)
}
ResumeVcpuErr(id: u8) {
display("Failed to resume vcpu{}.", id)
}
DestroyVcpuErr(id: u8) {
display("Failed to destroy vcpu{}.", id)
}
}
}
}
mod micro_vm;
mod standard_vm;
#[cfg(target_arch = "x86_64")]
mod vm_state;
use std::collections::BTreeMap;
use std::fs::remove_file;
use std::net::TcpListener;
use std::os::unix::{io::AsRawFd, net::UnixListener};
use std::path::Path;
use std::sync::{Arc, Barrier, Mutex, Weak};
use error_chain::bail;
use kvm_ioctls::VcpuFd;
use vmm_sys_util::{epoll::EventSet, eventfd::EventFd};
pub use micro_vm::LightMachine;
#[cfg(target_arch = "x86_64")]
use address_space::KvmIoListener;
use address_space::{
create_host_mmaps, set_host_memory_policy, AddressSpace, KvmMemoryListener, Region,
};
use cpu::{ArchCPU, CPUBootConfig, CPUInterface, CPUTopology, CPU};
use devices::legacy::FwCfgOps;
#[cfg(target_arch = "aarch64")]
use devices::InterruptController;
use errors::{ErrorKind, Result, ResultExt};
use hypervisor::kvm::KVM_FDS;
#[cfg(not(target_env = "musl"))]
use machine_manager::config::parse_gpu;
use machine_manager::config::{
complete_numa_node, get_multi_function, get_pci_bdf, parse_balloon, parse_blk, parse_device_id,
parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, parse_root_port,
parse_usb_keyboard, parse_usb_tablet, parse_vfio, parse_virtconsole, parse_virtio_serial,
parse_vsock, parse_xhci, BootIndexInfo, Incoming, MachineMemConfig, MigrateMode, NumaConfig,
NumaDistance, NumaNode, NumaNodes, ObjConfig, PFlashConfig, PciBdf, SerialConfig, VfioConfig,
VmConfig, FAST_UNPLUG_ON,
};
use machine_manager::{
event_loop::EventLoop,
machine::{KvmVmState, MachineInterface},
};
use migration::MigrationManager;
use pci::{PciBus, PciDevOps, PciHost, RootPort};
use standard_vm::errors::Result as StdResult;
pub use standard_vm::StdMachine;
use sysbus::{SysBus, SysBusDevOps};
use usb::{
bus::BusDeviceMap, keyboard::UsbKeyboard, tablet::UsbTablet, usb::UsbDeviceOps,
xhci::xhci_pci::XhciPciDevice, INPUT,
};
use util::{
arg_parser,
loop_context::{EventNotifier, NotifierCallback, NotifierOperation},
seccomp::{BpfRule, SeccompOpt, SyscallFilter},
};
use vfio::{VfioDevice, VfioPciDevice};
#[cfg(not(target_env = "musl"))]
use virtio::Gpu;
use virtio::{
balloon_allow_list, Balloon, Block, BlockState, Console, Rng, RngState, VhostKern, VhostUser,
VirtioConsoleState, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState,
VirtioPciDevice,
};
pub trait MachineOps {
/// Calculate the ranges of memory according to architecture.
///
/// # Arguments
///
/// * `mem_size` - memory size of VM.
///
/// # Returns
///
/// A array of ranges, it's element represents (start_addr, size).
/// On x86_64, there is a gap ranged from (4G - 768M) to 4G, which will be skipped.
fn arch_ram_ranges(&self, mem_size: u64) -> Vec<(u64, u64)>;
fn load_boot_source(&self, fwcfg: Option<&Arc<Mutex<dyn FwCfgOps>>>) -> Result<CPUBootConfig>;
/// Init I/O & memory address space and mmap guest memory.
///
/// # Arguments
///
/// * `mem_config` - Memory setting.
/// * `sys_io` - IO address space required for x86_64.
/// * `sys_mem` - Memory address space.
fn init_memory(
&self,
mem_config: &MachineMemConfig,
#[cfg(target_arch = "x86_64")] sys_io: &Arc<AddressSpace>,
sys_mem: &Arc<AddressSpace>,
nr_cpus: u8,
) -> Result<()> {
// KVM_CREATE_VM system call is invoked when KVM_FDS is used for the first time. The system
// call registers some notifier functions in the KVM, which are frequently triggered when
// doing memory prealloc.To avoid affecting memory prealloc performance, create_host_mmaps
// needs to be invoked first.
let mut mem_mappings = Vec::new();
let migrate_info = self.get_migrate_info();
if migrate_info.0 != MigrateMode::File {
let ram_ranges = self.arch_ram_ranges(mem_config.mem_size);
mem_mappings = create_host_mmaps(&ram_ranges, mem_config, nr_cpus)
.chain_err(|| "Failed to mmap guest ram.")?;
set_host_memory_policy(&mem_mappings, &mem_config.mem_zones)
.chain_err(|| "Failed to set host memory NUMA policy.")?;
}
sys_mem
.register_listener(Arc::new(Mutex::new(KvmMemoryListener::new(
KVM_FDS.load().fd.as_ref().unwrap().get_nr_memslots() as u32,
))))
.chain_err(|| "Failed to register KVM listener for memory space.")?;
#[cfg(target_arch = "x86_64")]
sys_io
.register_listener(Arc::new(Mutex::new(KvmIoListener::default())))
.chain_err(|| "Failed to register KVM listener for I/O address space.")?;
if migrate_info.0 != MigrateMode::File {
for mmap in mem_mappings.iter() {
let base = mmap.start_address().raw_value();
let size = mmap.size();
sys_mem
.root()
.add_subregion(Region::init_ram_region(mmap.clone()), base)
.chain_err(|| ErrorKind::RegMemRegionErr(base, size))?;
}
}
MigrationManager::register_memory_instance(sys_mem.clone());
Ok(())
}
/// Init vcpu register with boot message.
///
/// # Arguments
///
/// * `vm` - `MachineInterface` to obtain functions cpu can use.
/// * `nr_cpus` - The number of vcpus.
/// * `fds` - File descriptors obtained by creating new Vcpu in KVM.
/// * `boot_cfg` - Boot message generated by reading boot source to guest memory.
fn init_vcpu(
vm: Arc<Mutex<dyn MachineInterface + Send + Sync>>,
nr_cpus: u8,
topology: &CPUTopology,
fds: &[Arc<VcpuFd>],
boot_cfg: &Option<CPUBootConfig>,
) -> Result<Vec<Arc<CPU>>>
where
Self: Sized,
{
let mut cpus = Vec::<Arc<CPU>>::new();
for vcpu_id in 0..nr_cpus {
#[cfg(target_arch = "aarch64")]
let arch_cpu = ArchCPU::new(u32::from(vcpu_id));
#[cfg(target_arch = "x86_64")]
let arch_cpu = ArchCPU::new(u32::from(vcpu_id), u32::from(nr_cpus));
let cpu = Arc::new(CPU::new(
fds[vcpu_id as usize].clone(),
vcpu_id,
Arc::new(Mutex::new(arch_cpu)),
vm.clone(),
));
cpus.push(cpu.clone());
MigrationManager::register_cpu_instance(cpu::ArchCPU::descriptor(), cpu, vcpu_id);
}
if let Some(boot_config) = boot_cfg {
for cpu_index in 0..nr_cpus as usize {
cpus[cpu_index as usize]
.realize(boot_config, topology)
.chain_err(|| {
format!(
"Failed to realize arch cpu register for CPU {}/KVM",
cpu_index
)
})?;
}
}
Ok(cpus)
}
/// Add interrupt controller.
///
/// # Arguments
///
/// * `vcpu_count` - The number of vcpu.
fn init_interrupt_controller(&mut self, vcpu_count: u64) -> Result<()>;
/// Add RTC device.
fn add_rtc_device(&mut self, #[cfg(target_arch = "x86_64")] mem_size: u64) -> Result<()>;
/// Add serial device.
///
/// # Arguments
///
/// * `config` - Device configuration.
fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()>;
/// Add block device.
///
/// # Arguments
///
/// * `vm_config` - VM configuration.
/// * `cfg_args` - Device configuration args.
fn add_virtio_mmio_block(&mut self, _vm_config: &mut VmConfig, _cfg_args: &str) -> Result<()> {
bail!("Virtio mmio devices Not supported!");
}
/// Add virtio mmio vsock device.
///
/// # Arguments
///
/// * `cfg_args` - Device configuration.
fn add_virtio_vsock(&mut self, cfg_args: &str) -> Result<()> {
let device_cfg = parse_vsock(cfg_args)?;
let sys_mem = self.get_sys_mem().clone();
let vsock = Arc::new(Mutex::new(VhostKern::Vsock::new(&device_cfg, &sys_mem)));
if cfg_args.contains("vhost-vsock-device") {
let device = VirtioMmioDevice::new(&sys_mem, vsock.clone());
MigrationManager::register_device_instance(
VirtioMmioState::descriptor(),
self.realize_virtio_mmio_device(device)
.chain_err(|| ErrorKind::RlzVirtioMmioErr)?,
&device_cfg.id,
);
} else {
let bdf = get_pci_bdf(cfg_args)?;
let multi_func = get_multi_function(cfg_args)?;
let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?;
let virtio_pci_device = VirtioPciDevice::new(
device_cfg.id.clone(),
devfn,
sys_mem,
vsock.clone(),
parent_bus,
multi_func,
);
virtio_pci_device
.realize()
.chain_err(|| "Failed to add virtio pci vsock device")?;
}
MigrationManager::register_device_instance(
VhostKern::VsockState::descriptor(),
vsock,
&device_cfg.id,
);
Ok(())
}
fn realize_virtio_mmio_device(
&mut self,
_dev: VirtioMmioDevice,
) -> Result<Arc<Mutex<VirtioMmioDevice>>> {
bail!("Virtio mmio devices not supported");
}
fn get_sys_mem(&mut self) -> &Arc<AddressSpace>;
fn get_vm_config(&self) -> &Mutex<VmConfig>;
/// Get migration mode and path from VM config. There are four modes in total:
/// Tcp, Unix, File and Unknown.
fn get_migrate_info(&self) -> Incoming;
/// Get the bus device map. The map stores the mapping between bus name and bus device.
/// The bus device is the device which can attach other devices.
fn get_bus_device(&mut self) -> Option<&BusDeviceMap> {
None
}
/// Add net device.
///
/// # Arguments
///
/// * `vm_config` - VM configuration.
/// * `cfg_args` - Device configuration args.
fn add_virtio_mmio_net(&mut self, _vm_config: &mut VmConfig, _cfg_args: &str) -> Result<()> {
bail!("Virtio mmio device Not supported!");
}
fn add_virtio_balloon(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> {
let device_cfg = parse_balloon(vm_config, cfg_args)?;
let sys_mem = self.get_sys_mem();
let balloon = Arc::new(Mutex::new(Balloon::new(&device_cfg, sys_mem.clone())));
Balloon::object_init(balloon.clone());
if cfg_args.contains("virtio-balloon-device") {
let device = VirtioMmioDevice::new(sys_mem, balloon);
self.realize_virtio_mmio_device(device)?;
} else {
let name = device_cfg.id;
let bdf = get_pci_bdf(cfg_args)?;
let multi_func = get_multi_function(cfg_args)?;
let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?;
let sys_mem = self.get_sys_mem().clone();
let virtio_pci_device =
VirtioPciDevice::new(name, devfn, sys_mem, balloon, parent_bus, multi_func);
virtio_pci_device
.realize()
.chain_err(|| "Failed to add virtio pci balloon device")?;
}
Ok(())
}
/// Add console device.
///
/// # Arguments
///
/// * `vm_config` - VM configuration.
/// * `cfg_args` - Device configuration args.
fn add_virtio_console(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> {
let device_cfg = parse_virtconsole(vm_config, cfg_args)?;
let sys_mem = self.get_sys_mem();
let console = Arc::new(Mutex::new(Console::new(device_cfg.clone())));
if let Some(serial) = &vm_config.virtio_serial {
if serial.pci_bdf.is_none() {
let device = VirtioMmioDevice::new(sys_mem, console.clone());
MigrationManager::register_device_instance(
VirtioMmioState::descriptor(),
self.realize_virtio_mmio_device(device)
.chain_err(|| ErrorKind::RlzVirtioMmioErr)?,
&device_cfg.id,
);
} else {
let virtio_serial_info = if let Some(serial_info) = &vm_config.virtio_serial {
serial_info
} else {
bail!("No virtio-serial-pci device configured for virtconsole");
};
// Reasonable, because for virtio-serial-pci device, the bdf has been checked.
let bdf = virtio_serial_info.pci_bdf.clone().unwrap();
let multi_func = virtio_serial_info.multifunction;
let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?;
let sys_mem = self.get_sys_mem().clone();
let virtio_pci_device = VirtioPciDevice::new(
device_cfg.id.clone(),
devfn,
sys_mem,
console.clone(),
parent_bus,
multi_func,
);
virtio_pci_device
.realize()
.chain_err(|| "Failed to add virtio pci console device")?;
}
} else {
bail!("No virtio-serial-bus specified");
}
MigrationManager::register_device_instance(
VirtioConsoleState::descriptor(),
console,
&device_cfg.id,
);
Ok(())
}
fn add_virtio_serial(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> {
parse_virtio_serial(vm_config, cfg_args)?;
Ok(())
}
/// Add virtio-rng device.
///
/// # Arguments
///
/// * `vm_config` - VM configuration.
/// * `cfg_args` - Device configuration arguments.
fn add_virtio_rng(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> {
let device_cfg = parse_rng_dev(vm_config, cfg_args)?;
let sys_mem = self.get_sys_mem();
let rng_dev = Arc::new(Mutex::new(Rng::new(device_cfg.clone())));
if cfg_args.contains("virtio-rng-device") {
let device = VirtioMmioDevice::new(sys_mem, rng_dev.clone());
self.realize_virtio_mmio_device(device)
.chain_err(|| "Failed to add virtio mmio rng device")?;
} else {
let bdf = get_pci_bdf(cfg_args)?;
let multi_func = get_multi_function(cfg_args)?;
let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?;
let sys_mem = self.get_sys_mem().clone();
let vitio_pci_device = VirtioPciDevice::new(
device_cfg.id.clone(),
devfn,
sys_mem,
rng_dev.clone(),
parent_bus,
multi_func,
);
vitio_pci_device
.realize()
.chain_err(|| "Failed to add pci rng device")?;
}
MigrationManager::register_device_instance(RngState::descriptor(), rng_dev, &device_cfg.id);
Ok(())
}
fn get_pci_host(&mut self) -> StdResult<&Arc<Mutex<PciHost>>> {
bail!("No pci host found");
}
fn get_sys_bus(&mut self) -> &SysBus;
fn get_fwcfg_dev(&mut self) -> Result<Arc<Mutex<dyn FwCfgOps>>> {
bail!("No FwCfg deivce found");
}
fn get_boot_order_list(&self) -> Option<Arc<Mutex<Vec<BootIndexInfo>>>> {
None
}
fn reset_all_devices(&mut self) -> Result<()> {
let sysbus = self.get_sys_bus();
for dev in sysbus.devices.iter() {
dev.lock()
.unwrap()
.reset()
.chain_err(|| "Fail to reset sysbus device")?;
}
if let Ok(pci_host) = self.get_pci_host() {
pci_host
.lock()
.unwrap()
.reset()
.chain_err(|| "Fail to reset pci host")?;
}
Ok(())
}
fn check_device_id_existed(&mut self, name: &str) -> Result<()> {
// If there is no pci bus, skip the id check, such as micro vm.
if let Ok(pci_host) = self.get_pci_host() {
// Because device_del needs an id when removing a device, it's necessary to ensure that the id is unique.
if name.is_empty() {
bail!("Device id is empty");
}
if PciBus::find_attached_bus(&pci_host.lock().unwrap().root_bus, name).is_some() {
bail!("Device id {} existed", name);
}
}
Ok(())
}
fn reset_fwcfg_boot_order(&mut self) -> Result<()> {
// unwrap is safe because stand machine always make sure it not return null.
let boot_order_vec = self.get_boot_order_list().unwrap();
let mut locked_boot_order_vec = boot_order_vec.lock().unwrap().clone();
locked_boot_order_vec.sort_by(|x, y| x.boot_index.cmp(&y.boot_index));
let mut fwcfg_boot_order_string = String::new();
for item in &locked_boot_order_vec {
fwcfg_boot_order_string.push_str(&item.dev_path);
fwcfg_boot_order_string.push('\n');
}
fwcfg_boot_order_string.push('\0');
let fwcfg = self.get_fwcfg_dev()?;
fwcfg
.lock()
.unwrap()
.modify_file_entry("bootorder", fwcfg_boot_order_string.as_bytes().to_vec())
.chain_err(|| "Fail to add bootorder entry for standard VM.")?;
Ok(())
}
/// Check the boot index of device is duplicated or not.
///
/// # Arguments
///
/// * `bootindex` - The boot index of the device.
fn check_bootindex(&mut self, boot_index: u8) -> Result<()> {
// Unwrap is safe because StdMachine will overwrite this function,
// which ensure boot_order_list is not None.
let boot_order_list = self.get_boot_order_list().unwrap();
if boot_order_list
.lock()
.unwrap()
.iter()
.any(|item| item.boot_index == boot_index)
{
bail!("Failed to add duplicated bootindex {}.", boot_index);
}
Ok(())
}
/// Add boot index of device.
///
/// # Arguments
///
/// * `bootindex` - The boot index of the device.
/// * `dev_path` - The firmware device path of the device.
/// * `dev_id` - The id of the device.
fn add_bootindex_devices(&mut self, boot_index: u8, dev_path: &str, dev_id: &str) {
let boot_order_list = self.get_boot_order_list().unwrap();
boot_order_list.lock().unwrap().push(BootIndexInfo {
boot_index,
id: dev_id.to_string(),
dev_path: dev_path.to_string(),
});
}
/// Delete boot index of device.
///
/// # Arguments
///
/// * `dev_id` - The id of the device.
fn del_bootindex_devices(&self, dev_id: &str) {
// Unwrap is safe because StdMachine will overwrite this function,
// which ensure boot_order_list is not None.
let boot_order_list = self.get_boot_order_list().unwrap();
let mut locked_boot_order_list = boot_order_list.lock().unwrap();
locked_boot_order_list.retain(|item| item.id != dev_id);
}
fn add_virtio_pci_blk(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> {
let bdf = get_pci_bdf(cfg_args)?;
let multi_func = get_multi_function(cfg_args)?;
let device_cfg = parse_blk(vm_config, cfg_args)?;
if let Some(bootindex) = device_cfg.boot_index {
self.check_bootindex(bootindex)
.chain_err(|| "Fail to add virtio pci blk device for invalid bootindex")?;
}
let device = Arc::new(Mutex::new(Block::new(device_cfg.clone())));
let pci_dev = self
.add_virtio_pci_device(&device_cfg.id, &bdf, device.clone(), multi_func, false)
.chain_err(|| "Failed to add virtio pci device")?;
if let Some(bootindex) = device_cfg.boot_index {
if let Some(dev_path) = pci_dev.lock().unwrap().get_dev_path() {
self.add_bootindex_devices(bootindex, &dev_path, &device_cfg.id);
}
}
MigrationManager::register_device_instance(
BlockState::descriptor(),
device,
&device_cfg.id,
);
self.reset_bus(&device_cfg.id)?;
Ok(())
}
fn add_virtio_pci_net(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> {
let bdf = get_pci_bdf(cfg_args)?;
let multi_func = get_multi_function(cfg_args)?;
let device_cfg = parse_net(vm_config, cfg_args)?;
let mut need_irqfd = false;
let device: Arc<Mutex<dyn VirtioDevice>> = if device_cfg.vhost_type.is_some() {
if device_cfg.vhost_type == Some(String::from("vhost-kernel")) {
Arc::new(Mutex::new(VhostKern::Net::new(
&device_cfg,
self.get_sys_mem(),
)))
} else {
need_irqfd = true;
Arc::new(Mutex::new(VhostUser::Net::new(
&device_cfg,
self.get_sys_mem(),
)))
}
} else {
let device = Arc::new(Mutex::new(virtio::Net::new(device_cfg.clone())));
MigrationManager::register_device_instance(
VirtioNetState::descriptor(),
device.clone(),
&device_cfg.id,
);
device
};
self.add_virtio_pci_device(&device_cfg.id, &bdf, device, multi_func, need_irqfd)?;
self.reset_bus(&device_cfg.id)?;
Ok(())
}
fn create_vfio_pci_device(
&mut self,
id: &str,
bdf: &PciBdf,
host: &str,
sysfsdev: &str,
multifunc: bool,
) -> Result<()> {
let (devfn, parent_bus) = self.get_devfn_and_parent_bus(bdf)?;
let path;
if !host.is_empty() {
path = format!("/sys/bus/pci/devices/{}", host);
} else {
path = sysfsdev.to_string();
}
let device = VfioDevice::new(Path::new(&path), self.get_sys_mem())
.chain_err(|| "Failed to create vfio device.")?;
let vfio_pci = VfioPciDevice::new(
device,
devfn,
id.to_string(),
parent_bus,
multifunc,
self.get_sys_mem().clone(),
);
VfioPciDevice::realize(vfio_pci).chain_err(|| "Failed to realize vfio-pci device.")?;
Ok(())
}
fn add_vfio_device(&mut self, cfg_args: &str) -> Result<()> {
let device_cfg: VfioConfig = parse_vfio(cfg_args)?;
let bdf = get_pci_bdf(cfg_args)?;
let multifunc = get_multi_function(cfg_args)?;
self.create_vfio_pci_device(
&device_cfg.id,
&bdf,
&device_cfg.host,
&device_cfg.sysfsdev,
multifunc,
)?;
self.reset_bus(&device_cfg.id)?;
Ok(())
}
#[cfg(not(target_env = "musl"))]
fn add_virtio_pci_gpu(&mut self, cfg_args: &str) -> Result<()> {
let bdf = get_pci_bdf(cfg_args)?;
let multi_func = get_multi_function(cfg_args)?;
let device_cfg = parse_gpu(cfg_args)?;
let device = Arc::new(Mutex::new(Gpu::new(device_cfg.clone())));
self.add_virtio_pci_device(&device_cfg.id, &bdf, device, multi_func, false)?;
Ok(())
}
fn get_devfn_and_parent_bus(&mut self, bdf: &PciBdf) -> StdResult<(u8, Weak<Mutex<PciBus>>)> {
let pci_host = self.get_pci_host()?;
let bus = pci_host.lock().unwrap().root_bus.clone();
let pci_bus = PciBus::find_bus_by_name(&bus, &bdf.bus);
if pci_bus.is_none() {
bail!("Parent bus :{} not found", &bdf.bus);
}
let parent_bus = Arc::downgrade(&pci_bus.unwrap());
let devfn = (bdf.addr.0 << 3) + bdf.addr.1;
Ok((devfn, parent_bus))
}
fn add_pci_root_port(&mut self, cfg_args: &str) -> Result<()> {
let bdf = get_pci_bdf(cfg_args)?;
let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?;
let device_cfg = parse_root_port(cfg_args)?;
let pci_host = self.get_pci_host()?;
let bus = pci_host.lock().unwrap().root_bus.clone();
if PciBus::find_bus_by_name(&bus, &device_cfg.id).is_some() {
bail!("ID {} already exists.");
}
let rootport = RootPort::new(
device_cfg.id,
devfn,
device_cfg.port,
parent_bus,
device_cfg.multifunction,
);
rootport
.realize()
.chain_err(|| "Failed to add pci root port")?;
Ok(())
}
fn add_virtio_pci_device(
&mut self,
id: &str,
bdf: &PciBdf,
device: Arc<Mutex<dyn VirtioDevice>>,
multi_func: bool,
need_irqfd: bool,
) -> Result<Arc<Mutex<dyn PciDevOps>>> {
let (devfn, parent_bus) = self.get_devfn_and_parent_bus(bdf)?;
let sys_mem = self.get_sys_mem();
let mut pcidev = VirtioPciDevice::new(
id.to_string(),
devfn,
sys_mem.clone(),
device,
parent_bus,
multi_func,
);
if need_irqfd {
pcidev.enable_need_irqfd();
}
let clone_pcidev = Arc::new(Mutex::new(pcidev.clone()));
pcidev
.realize()
.chain_err(|| "Failed to add virtio pci device")?;
Ok(clone_pcidev)
}
/// Set the parent bus slot on when device attached
fn reset_bus(&mut self, dev_id: &str) -> Result<()> {
let pci_host = self.get_pci_host()?;
let locked_pci_host = pci_host.lock().unwrap();
let bus =
if let Some((bus, _)) = PciBus::find_attached_bus(&locked_pci_host.root_bus, dev_id) {
bus
} else {
bail!("Bus not found, dev id {}", dev_id);
};
let locked_bus = bus.lock().unwrap();
if locked_bus.name == "pcie.0" {
// No need to reset root bus
return Ok(());
}
let parent_bridge = if let Some(bridge) = locked_bus.parent_bridge.as_ref() {
bridge
} else {
bail!("Parent bridge does not exist, dev id {}", dev_id);
};
let dev = parent_bridge.upgrade().unwrap();
let locked_dev = dev.lock().unwrap();
let name = locked_dev.name();
drop(locked_dev);
let mut devfn = None;
let locked_bus = locked_pci_host.root_bus.lock().unwrap();
for (id, dev) in &locked_bus.devices {
if dev.lock().unwrap().name() == name {
devfn = Some(*id);
break;
}
}
drop(locked_bus);
// It's safe to call devfn.unwrap(), because the bus exists.
match locked_pci_host.find_device(0, devfn.unwrap()) {
Some(dev) => dev
.lock()
.unwrap()
.reset(false)
.chain_err(|| "Failed to reset bus"),
None => bail!("Failed to found device"),
}
}
/// Init vm global config.
///
/// # Arguments
///
/// * `vm_config` - VM Configuration.
fn init_global_config(&mut self, vm_config: &mut VmConfig) -> Result<()> {
let fast_unplug = vm_config
.global_config
.get("pcie-root-port.fast-unplug")
.map_or(false, |val| val == FAST_UNPLUG_ON);
RootPort::set_fast_unplug_feature(fast_unplug);
Ok(())
}
/// Add numa nodes information to standard machine.
///
/// # Arguments
///
/// * `vm_config` - VM Configuration.
fn add_numa_nodes(&mut self, vm_config: &mut VmConfig) -> Result<Option<NumaNodes>> {
if vm_config.numa_nodes.is_empty() {
return Ok(None);
}
let mut numa_nodes: NumaNodes = BTreeMap::new();
vm_config.numa_nodes.sort_by(|p, n| n.0.cmp(&p.0));
for numa in vm_config.numa_nodes.iter() {
match numa.0.as_str() {
"node" => {
let numa_config: NumaConfig = parse_numa_mem(numa.1.as_str())?;
if numa_nodes.contains_key(&numa_config.numa_id) {
bail!("Numa node id is repeated {}", numa_config.numa_id);
}
let mut numa_node = NumaNode {
cpus: numa_config.cpus,
..Default::default()
};
if let Some(object_cfg) = vm_config.object.remove(&numa_config.mem_dev) {
if let ObjConfig::Zone(zone_config) = object_cfg {
numa_node.size = zone_config.size;
}
} else {
bail!(
"Object for memory-backend-ram {} config not found",
numa_config.mem_dev
);
}
numa_nodes.insert(numa_config.numa_id, numa_node);
}
"dist" => {
let dist: (u32, NumaDistance) = parse_numa_distance(numa.1.as_str())?;
if !numa_nodes.contains_key(&dist.0) {
bail!("Numa node id is not found {}", dist.0);
}
if !numa_nodes.contains_key(&dist.1.destination) {
bail!("Numa node id is not found {}", dist.1.destination);
}
if let Some(n) = numa_nodes.get_mut(&dist.0) {
if n.distances.contains_key(&dist.1.destination) {
bail!(
"Numa destination info {} repeat settings",
dist.1.destination
);
}
n.distances.insert(dist.1.destination, dist.1.distance);
}
}
_ => {
bail!("Unsupported args for NUMA node: {}", numa.0.as_str());
}
}
}
// Complete user parameters if necessary.
complete_numa_node(
&mut numa_nodes,
vm_config.machine_config.nr_cpus,
vm_config.machine_config.mem_config.mem_size,
)?;
Ok(Some(numa_nodes))
}
/// Add usb xhci controller.
///
/// # Arguments
///
/// * `cfg_args` - XHCI Configuration.
fn add_usb_xhci(&mut self, cfg_args: &str) -> Result<()> {
let bdf = get_pci_bdf(cfg_args)?;
let device_cfg = parse_xhci(cfg_args)?;
let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?;
let bus_device = if let Some(bus_device) = self.get_bus_device() {
bus_device.clone()
} else {
bail!("No bus device found");
};
let pcidev = XhciPciDevice::new(
&device_cfg.id,
devfn,
parent_bus,
self.get_sys_mem(),
bus_device,
);
pcidev
.realize()
.chain_err(|| "Failed to realize usb xhci device")?;
Ok(())
}
/// Add usb keyboard.
///
/// # Arguments
///
/// * `cfg_args` - Keyboard Configuration.
fn add_usb_keyboard(&mut self, cfg_args: &str) -> Result<()> {
let device_cfg = parse_usb_keyboard(cfg_args)?;
let keyboard = UsbKeyboard::new(device_cfg.id);
let kbd = keyboard
.realize()
.chain_err(|| "Failed to realize usb keyboard device")?;
if let Some(bus_device) = self.get_bus_device() {
let locked_dev = bus_device.lock().unwrap();
if let Some(ctrl) = locked_dev.get("usb.0") {
let mut locked_ctrl = ctrl.lock().unwrap();
locked_ctrl
.attach_device(&(kbd.clone() as Arc<Mutex<dyn UsbDeviceOps>>))
.chain_err(|| "Failed to attach keyboard device")?;
} else {
bail!("No usb controller found");
}
} else {
bail!("No bus device found");
}
let mut locked_input = INPUT.lock().unwrap();
locked_input.keyboard = Some(kbd);
Ok(())
}
/// Add usb tablet.
///
/// # Arguments
///
/// * `cfg_args` - Tablet Configuration.
fn add_usb_tablet(&mut self, cfg_args: &str) -> Result<()> {
let device_cfg = parse_usb_tablet(cfg_args)?;
let tablet = UsbTablet::new(device_cfg.id);
let tbt = tablet
.realize()
.chain_err(|| "Failed to realize usb tablet device")?;
if let Some(bus_device) = self.get_bus_device() {
let locked_dev = bus_device.lock().unwrap();
if let Some(ctrl) = locked_dev.get("usb.0") {
let mut locked_ctrl = ctrl.lock().unwrap();
locked_ctrl
.attach_device(&(tbt.clone() as Arc<Mutex<dyn UsbDeviceOps>>))
.chain_err(|| "Failed to attach tablet device")?;
} else {
bail!("No usb controller found");
}
} else {
bail!("No bus device list found");
}
let mut locked_input = INPUT.lock().unwrap();
locked_input.tablet = Some(tbt);
Ok(())
}
/// Add peripheral devices.
///
/// # Arguments
///
/// * `vm_config` - VM Configuration.
fn add_devices(&mut self, vm_config: &mut VmConfig) -> Result<()> {
self.add_rtc_device(
#[cfg(target_arch = "x86_64")]
vm_config.machine_config.mem_config.mem_size,
)
.chain_err(|| ErrorKind::AddDevErr("RTC".to_string()))?;
let cloned_vm_config = vm_config.clone();
if let Some(serial) = cloned_vm_config.serial.as_ref() {
self.add_serial_device(serial)
.chain_err(|| ErrorKind::AddDevErr("serial".to_string()))?;
}
if let Some(pflashs) = cloned_vm_config.pflashs.as_ref() {
self.add_pflash_device(pflashs)
.chain_err(|| ErrorKind::AddDevErr("pflash".to_string()))?;
}
for dev in &cloned_vm_config.devices {
let cfg_args = dev.1.as_str();
// Check whether the device id exists to ensure device uniqueness.
let id = parse_device_id(cfg_args)?;
self.check_device_id_existed(&id)
.chain_err(|| format!("Failed to check device id: config {}", cfg_args))?;
match dev.0.as_str() {
"virtio-blk-device" => {
self.add_virtio_mmio_block(vm_config, cfg_args)?;
}
"virtio-blk-pci" => {
self.add_virtio_pci_blk(vm_config, cfg_args)?;
}
"virtio-net-device" => {
self.add_virtio_mmio_net(vm_config, cfg_args)?;
}
"virtio-net-pci" => {
self.add_virtio_pci_net(vm_config, cfg_args)?;
}
"pcie-root-port" => {
self.add_pci_root_port(cfg_args)?;
}
"vhost-vsock-pci" | "vhost-vsock-device" => {
self.add_virtio_vsock(cfg_args)?;
}
"virtio-balloon-device" | "virtio-balloon-pci" => {
self.add_virtio_balloon(vm_config, cfg_args)?;
}
"virtio-serial-device" | "virtio-serial-pci" => {
self.add_virtio_serial(vm_config, cfg_args)?;
}
"virtconsole" => {
self.add_virtio_console(vm_config, cfg_args)?;
}
"virtio-rng-device" | "virtio-rng-pci" => {
self.add_virtio_rng(vm_config, cfg_args)?;
}
"vfio-pci" => {
self.add_vfio_device(cfg_args)?;
}
"nec-usb-xhci" => {
self.add_usb_xhci(cfg_args)?;
}
"usb-kbd" => {
self.add_usb_keyboard(cfg_args)?;
}
"usb-tablet" => {
self.add_usb_tablet(cfg_args)?;
}
#[cfg(not(target_env = "musl"))]
"virtio-gpu-pci" => {
self.add_virtio_pci_gpu(cfg_args)?;
}
_ => {
bail!("Unsupported device: {:?}", dev.0.as_str());
}
}
}
Ok(())
}
fn add_pflash_device(&mut self, _configs: &[PFlashConfig]) -> Result<()> {
bail!("Pflash device is not supported!");
}
/// Return the syscall whitelist for seccomp.
fn syscall_whitelist(&self) -> Vec<BpfRule>;
/// Register seccomp rules in syscall whitelist to seccomp.
fn register_seccomp(&self, balloon_enable: bool) -> Result<()> {
let mut seccomp_filter = SyscallFilter::new(SeccompOpt::Trap);
let mut bpf_rules = self.syscall_whitelist();
if balloon_enable {
balloon_allow_list(&mut bpf_rules);
}
for bpf_rule in &mut bpf_rules {
seccomp_filter.push(bpf_rule);
}
seccomp_filter
.realize()
.chain_err(|| "Failed to init seccomp filter.")?;
Ok(())
}
/// Register event notifier for power button of mainboard.
///
/// # Arguments
///
/// * `power_button` - Eventfd of the power button.
fn register_power_event(&self, power_button: &EventFd) -> Result<()> {
let power_button = power_button.try_clone().unwrap();
let button_fd = power_button.as_raw_fd();
let power_button_handler: Arc<Mutex<Box<NotifierCallback>>> =
Arc::new(Mutex::new(Box::new(move |_, _| {
let _ret = power_button.read().unwrap();
None
})));
let notifier = EventNotifier::new(
NotifierOperation::AddShared,
button_fd,
None,
EventSet::IN,
vec![power_button_handler],
);
EventLoop::update_event(vec![notifier], None).chain_err(|| ErrorKind::RegNotifierErr)?;
Ok(())
}
/// Realize the machine.
///
/// # Arguments
///
/// * `vm` - The machine structure.
/// * `vm_config` - VM configuration.
fn realize(vm: &Arc<Mutex<Self>>, vm_config: &mut VmConfig) -> Result<()>
where
Self: Sized;
/// Run `LightMachine` with `paused` flag.
///
/// # Arguments
///
/// * `paused` - Flag for `paused` when `LightMachine` starts to run.
fn run(&self, paused: bool) -> Result<()>;
/// Start machine as `Running` or `Paused` state.
///
/// # Arguments
///
/// * `paused` - After started, paused all vcpu or not.
/// * `cpus` - Cpus vector restore cpu structure.
/// * `vm_state` - Vm kvm vm state.
fn vm_start(paused: bool, cpus: &[Arc<CPU>], vm_state: &mut KvmVmState) -> Result<()>
where
Self: Sized,
{
let nr_vcpus = cpus.len();
let cpus_thread_barrier = Arc::new(Barrier::new((nr_vcpus + 1) as usize));
for cpu_index in 0..nr_vcpus {
let cpu_thread_barrier = cpus_thread_barrier.clone();
let cpu = cpus[cpu_index as usize].clone();
CPU::start(cpu, cpu_thread_barrier, paused)
.chain_err(|| format!("Failed to run vcpu{}", cpu_index))?;
}
if paused {
*vm_state = KvmVmState::Paused;
} else {
*vm_state = KvmVmState::Running;
}
cpus_thread_barrier.wait();
Ok(())
}
/// Pause VM as `Paused` state, sleepy all vcpu thread.
///
/// # Arguments
///
/// * `cpus` - Cpus vector restore cpu structure.
/// * `vm_state` - Vm kvm vm state.
fn vm_pause(
cpus: &[Arc<CPU>],
#[cfg(target_arch = "aarch64")] irq_chip: &Option<Arc<InterruptController>>,
vm_state: &mut KvmVmState,
) -> Result<()>
where
Self: Sized,
{
for (cpu_index, cpu) in cpus.iter().enumerate() {
cpu.pause()
.chain_err(|| format!("Failed to pause vcpu{}", cpu_index))?;
}
#[cfg(target_arch = "aarch64")]
irq_chip.as_ref().unwrap().stop();
*vm_state = KvmVmState::Paused;
Ok(())
}
/// Resume VM as `Running` state, awaken all vcpu thread.
///
/// # Arguments
///
/// * `cpus` - Cpus vector restore cpu structure.
/// * `vm_state` - Vm kvm vm state.
fn vm_resume(cpus: &[Arc<CPU>], vm_state: &mut KvmVmState) -> Result<()>
where
Self: Sized,
{
for (cpu_index, cpu) in cpus.iter().enumerate() {
cpu.resume()
.chain_err(|| format!("Failed to resume vcpu{}", cpu_index))?;
}
*vm_state = KvmVmState::Running;
Ok(())
}
/// Destroy VM as `Shutdown` state, destroy vcpu thread.
///
/// # Arguments
///
/// * `cpus` - Cpus vector restore cpu structure.
/// * `vm_state` - Vm kvm vm state.
fn vm_destroy(cpus: &[Arc<CPU>], vm_state: &mut KvmVmState) -> Result<()>
where
Self: Sized,
{
for (cpu_index, cpu) in cpus.iter().enumerate() {
cpu.destroy()
.chain_err(|| format!("Failed to destroy vcpu{}", cpu_index))?;
}
*vm_state = KvmVmState::Shutdown;
Ok(())
}
/// Transfer VM state from `old` to `new`.
///
/// # Arguments
///
/// * `cpus` - Cpus vector restore cpu structure.
/// * `vm_state` - Vm kvm vm state.
/// * `old_state` - Old vm state want to leave.
/// * `new_state` - New vm state want to transfer to.
fn vm_state_transfer(
cpus: &[Arc<CPU>],
#[cfg(target_arch = "aarch64")] irq_chip: &Option<Arc<InterruptController>>,
vm_state: &mut KvmVmState,
old_state: KvmVmState,
new_state: KvmVmState,
) -> Result<()>
where
Self: Sized,
{
use KvmVmState::*;
if *vm_state != old_state {
bail!("Vm lifecycle error: state check failed.");
}
match (old_state, new_state) {
(Created, Running) => <Self as MachineOps>::vm_start(false, cpus, vm_state)
.chain_err(|| "Failed to start vm.")?,
(Running, Paused) => <Self as MachineOps>::vm_pause(
cpus,
#[cfg(target_arch = "aarch64")]
irq_chip,
vm_state,
)
.chain_err(|| "Failed to pause vm.")?,
(Paused, Running) => <Self as MachineOps>::vm_resume(cpus, vm_state)
.chain_err(|| "Failed to resume vm.")?,
(_, Shutdown) => {
<Self as MachineOps>::vm_destroy(cpus, vm_state)
.chain_err(|| "Failed to destroy vm.")?;
}
(_, _) => {
bail!("Vm lifecycle error: this transform is illegal.");
}
}
if *vm_state != new_state {
bail!(
"Vm lifecycle error: state '{:?} -> {:?}' transform failed.",
old_state,
new_state
);
}
Ok(())
}
}
/// Normal run or resume virtual machine from migration/snapshot .
///
/// # Arguments
///
/// * `vm` - virtual machine that implement `MachineOps`.
/// * `cmd_args` - Command arguments from user.
pub fn vm_run(
vm: &Arc<Mutex<dyn MachineOps + Send + Sync>>,
cmd_args: &arg_parser::ArgMatches,
) -> Result<()> {
let migrate = vm.lock().unwrap().get_migrate_info();
if migrate.0 == MigrateMode::Unknown {
vm.lock()
.unwrap()
.run(cmd_args.is_present("freeze_cpu"))
.chain_err(|| "Failed to start VM.")?;
} else {
start_incoming_migration(vm).chain_err(|| "Failed to start migration.")?;
}
Ok(())
}
/// Start incoming migration from destination.
fn start_incoming_migration(vm: &Arc<Mutex<dyn MachineOps + Send + Sync>>) -> Result<()> {
let (mode, path) = vm.lock().unwrap().get_migrate_info();
match mode {
MigrateMode::File => {
MigrationManager::restore_snapshot(&path).chain_err(|| "Failed to restore snapshot")?;
vm.lock()
.unwrap()
.run(false)
.chain_err(|| "Failed to start VM.")?;
}
MigrateMode::Unix => {
let listener = UnixListener::bind(&path)?;
let (mut sock, _) = listener.accept()?;
remove_file(&path)?;
MigrationManager::recv_migration(&mut sock)
.chain_err(|| "Failed to receive migration with unix mode")?;
vm.lock()
.unwrap()
.run(false)
.chain_err(|| "Failed to start VM.")?;
MigrationManager::finish_migration(&mut sock)
.chain_err(|| "Failed to finish migraton.")?;
}
MigrateMode::Tcp => {
let listener = TcpListener::bind(&path)?;
let mut sock = listener.accept().map(|(stream, _)| stream)?;
MigrationManager::recv_migration(&mut sock)
.chain_err(|| "Failed to receive migration with tcp mode")?;
vm.lock()
.unwrap()
.run(false)
.chain_err(|| "Failed to start VM.")?;
MigrationManager::finish_migration(&mut sock)
.chain_err(|| "Failed to finish migraton.")?;
}
MigrateMode::Unknown => {
bail!("Unknown migration mode");
}
}
// End the migration and reset the mode.
let locked_vm = vm.lock().unwrap();
let vm_config = locked_vm.get_vm_config();
if let Some((mode, _)) = vm_config.lock().unwrap().incoming.as_mut() {
*mode = MigrateMode::Unknown;
}
Ok(())
}

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/openeuler-stratovirt.git
git@gitlife.ru:oschina-mirror/openeuler-stratovirt.git
oschina-mirror
openeuler-stratovirt
openeuler-stratovirt
v2.2.0-rc5