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

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
lib.rs 48 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
Binfeng Wu Отправлено 3 лет назад 8a72582
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
// 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;
use machine_manager::config::{
complete_numa_node, get_multi_function, get_pci_bdf, parse_balloon, parse_blk, parse_device_id,
parse_gpu, 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,
};
use util::{
arg_parser,
loop_context::{EventNotifier, NotifierCallback, NotifierOperation},
seccomp::{BpfRule, SeccompOpt, SyscallFilter},
};
use vfio::{VfioDevice, VfioPciDevice};
use virtio::{
balloon_allow_list, Balloon, Block, BlockState, Console, Gpu, 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,
multifunc: bool,
) -> Result<()> {
let (devfn, parent_bus) = self.get_devfn_and_parent_bus(bdf)?;
let path = format!("/sys/bus/pci/devices/{}", host);
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, multifunc)?;
self.reset_bus(&device_cfg.id)?;
Ok(())
}
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 as Arc<Mutex<dyn UsbDeviceOps>>))
.chain_err(|| "Failed to attach keyboard device")?;
} else {
bail!("No usb controller found");
}
} else {
bail!("No bus device found");
}
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 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");
}
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)?;
}
"virtio-gpu-pci" => {
self.add_virtio_pci_gpu(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)?;
}
_ => {
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-rc3