From 56c17ebfe892f7c2f4aae85d93c16f34a1cbad2c Mon Sep 17 00:00:00 2001 From: Guo Xinle Date: Thu, 24 Sep 2020 20:20:22 +0800 Subject: [PATCH 1/5] device: add net test cases in net.rs Signed-off-by: Guo Xinle guoxinle1@huawei.com --- device_model/src/virtio/net.rs | 65 ++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/device_model/src/virtio/net.rs b/device_model/src/virtio/net.rs index 05b41b50a..3d6dcc3fa 100644 --- a/device_model/src/virtio/net.rs +++ b/device_model/src/virtio/net.rs @@ -704,3 +704,68 @@ impl VirtioDevice for Net { Ok(()) } } + +#[cfg(test)] +mod tests { + pub use super::super::*; + pub use super::*; + + #[test] + fn test_net_init() { + // test net new method + let mut net = Net::new(); + assert_eq!(net.device_features, 0); + assert_eq!(net.driver_features, 0); + + assert_eq!(net.tap.is_none(), true); + assert_eq!(net.sender.is_none(), true); + assert_eq!(net.net_cfg.mac.is_none(), true); + assert_eq!(net.net_cfg.tap_fd.is_none(), true); + assert_eq!(net.net_cfg.vhost_type.is_none(), true); + assert_eq!(net.net_cfg.vhost_fd.is_none(), true); + + // test net realize method + net.realize().unwrap(); + assert_eq!(net.device_type(), 1); + assert_eq!(net.queue_num(), 2); + assert_eq!(net.queue_size(), 256); + + // test read_config and write_config method + let wriet_data: Vec = vec![7; 4]; + let mut random_data: Vec = vec![0; 4]; + let mut origin_data: Vec = vec![0; 4]; + net.read_config(0x00, &mut origin_data).unwrap(); + + net.write_config(0x00, &wriet_data).unwrap(); + net.read_config(0x00, &mut random_data).unwrap(); + assert_eq!(random_data, wriet_data); + + net.write_config(0x00, &origin_data).unwrap(); + + // test boundary condition of offset and data parameters + let device_config = net.device_config.as_bytes(); + let len = device_config.len() as u64; + + let mut data: Vec = vec![0; 10]; + let offset: u64 = len + 1; + assert_eq!(net.read_config(offset, &mut data).is_ok(), false); + + let offset: u64 = len; + assert_eq!(net.read_config(offset, &mut data).is_ok(), false); + + let offset: u64 = 0; + assert_eq!(net.read_config(offset, &mut data).is_ok(), true); + + let offset: u64 = len; + let mut data: Vec = vec![0; 1]; + assert_eq!(net.write_config(offset, &mut data).is_ok(), false); + + let offset: u64 = len - 1; + let mut data: Vec = vec![0; 1]; + assert_eq!(net.write_config(offset, &mut data).is_ok(), true); + + let offset: u64 = 0; + let mut data: Vec = vec![0; len as usize]; + assert_eq!(net.write_config(offset, &mut data).is_ok(), true); + } +} -- Gitee From 2188bde42bc53618e920af46f8ae30f5d8ce566e Mon Sep 17 00:00:00 2001 From: Yang Xiaohe Date: Fri, 25 Sep 2020 10:51:52 +0800 Subject: [PATCH 2/5] Update Some tests in memory, cpu and interrupt controller. 1. If no KVM module enabled or no r/w permissions for /dev/kvm, omit the tests which use KVM module. 2. update some comments of tests. 3. Complete the error info when failed to open /dev/kvm. 4. Remove unneccessary allowance of clippy lints Signed-off-by: Yang Xiaohe --- address_space/src/listener.rs | 41 +++++++++++-------- device_model/src/cpu/x86_64/mod.rs | 15 ++++--- .../src/interrupt_controller/aarch64/mod.rs | 7 +++- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/address_space/src/listener.rs b/address_space/src/listener.rs index 3810d1dbb..66a37317f 100644 --- a/address_space/src/listener.rs +++ b/address_space/src/listener.rs @@ -518,11 +518,6 @@ mod test { } } - fn create_vm() -> VmFd { - let kvm = Kvm::new().expect("create kvm failed"); - kvm.create_vm().expect("create vm failed") - } - fn create_ram_range(addr: u64, size: u64, offset_in_region: u64) -> FlatRange { let mem_mapping = Arc::new(HostMemMapping::new(GuestAddress(addr), size, false).unwrap()); FlatRange { @@ -537,7 +532,11 @@ mod test { #[test] fn test_alloc_slot() { - let kml = KvmMemoryListener::new(34, Arc::new(create_vm())); + let kml = match Kvm::new().and_then(|kvm| kvm.create_vm()) { + Ok(vm_fd) => KvmMemoryListener::new(34, Arc::new(vm_fd)), + Err(_) => return, + }; + let host_addr = 0u64; assert_eq!(kml.get_free_slot(0, 100, host_addr).unwrap(), 0); assert_eq!(kml.get_free_slot(200, 100, host_addr).unwrap(), 1); @@ -553,21 +552,23 @@ mod test { #[test] fn test_add_del_ram_region() { - let vm = Arc::new(create_vm()); - let kml = KvmMemoryListener::new(34, vm.clone()); + let kml = match Kvm::new().and_then(|kvm| kvm.create_vm()) { + Ok(vm_fd) => KvmMemoryListener::new(34, Arc::new(vm_fd)), + Err(_) => return, + }; let ram_size = page_size(); let ram_fr1 = create_ram_range(0, ram_size, 0); kml.handle_request(Some(&ram_fr1), None, ListenerReqType::AddRegion) .unwrap(); - //flat-range already added, adding again should make an error + // flat-range already added, adding again should make an error assert!(kml .handle_request(Some(&ram_fr1), None, ListenerReqType::AddRegion) .is_err()); assert!(kml .handle_request(Some(&ram_fr1), None, ListenerReqType::DeleteRegion) .is_ok()); - //flat-range already deleted, deleting again should make an error + // flat-range already deleted, deleting again should make an error assert!(kml .handle_request(Some(&ram_fr1), None, ListenerReqType::DeleteRegion) .is_err()); @@ -575,8 +576,10 @@ mod test { #[test] fn test_add_region_align() { - let vm = Arc::new(create_vm()); - let kml = KvmMemoryListener::new(34, vm.clone()); + let kml = match Kvm::new().and_then(|kvm| kvm.create_vm()) { + Ok(vm_fd) => KvmMemoryListener::new(34, Arc::new(vm_fd)), + Err(_) => return, + }; // flat-range not aligned let page_size = page_size(); @@ -594,8 +597,10 @@ mod test { #[test] fn test_add_del_ioeventfd() { - let vm = Arc::new(create_vm()); - let kml = KvmMemoryListener::new(34, vm.clone()); + let kml = match Kvm::new().and_then(|kvm| kvm.create_vm()) { + Ok(vm_fd) => KvmMemoryListener::new(34, Arc::new(vm_fd)), + Err(_) => return, + }; let evtfd = generate_region_ioeventfd(4, None); assert!(kml @@ -619,7 +624,7 @@ mod test { .handle_request(None, Some(&evtfd), ListenerReqType::AddIoeventfd) .is_ok()); // deleting this ioeventfd returns an error, for the reason that - // function `unregister_ioevent` in kvm-ioctls package don't have an `data_match` argument + // function `unregister_ioevent` in kvm-ioctls package doesn't support `data_match` argument yet. assert!(kml .handle_request(None, Some(&evtfd), ListenerReqType::DeleteIoeventfd) .is_err()); @@ -628,8 +633,10 @@ mod test { #[test] #[cfg(target_arch = "x86_64")] fn test_kvm_io_listener() { - let vm = Arc::new(create_vm()); - let iol = KvmIoListener::new(vm.clone()); + let iol = match Kvm::new().and_then(|kvm| kvm.create_vm()) { + Ok(vm_fd) => KvmIoListener::new(Arc::new(vm_fd)), + Err(_) => return, + }; let evtfd = generate_region_ioeventfd(4, None); assert!(iol diff --git a/device_model/src/cpu/x86_64/mod.rs b/device_model/src/cpu/x86_64/mod.rs index 94ea36715..9dece1193 100644 --- a/device_model/src/cpu/x86_64/mod.rs +++ b/device_model/src/cpu/x86_64/mod.rs @@ -384,8 +384,8 @@ mod test { use super::*; use kvm_bindings::kvm_segment; use std::sync::Arc; - #[test] + #[test] fn test_x86_64_cpu() { let code_seg = kvm_segment { base: 0, @@ -429,10 +429,15 @@ mod test { idt_size: 8, pml4_start: 0x0000_9000, }; - let kvm = Kvm::new().unwrap(); - let vm = Arc::new(kvm.create_vm().unwrap()); - /* For `get_lapic` in realize function to work, - you need to create a irq_chip for VM before creating the VCPU. */ + + let vm = if let Ok(vm_fd) = Kvm::new().and_then(|kvm| kvm.create_vm()) { + Arc::new(vm_fd) + } else { + return; + }; + + // For `get_lapic` in realize function to work, + // you need to create a irq_chip for VM before creating the VCPU. vm.create_irq_chip().unwrap(); let vcpu = Arc::new(vm.create_vcpu(0).unwrap()); let mut x86_cpu = X86CPU::new(&vm, 0, 1); diff --git a/device_model/src/interrupt_controller/aarch64/mod.rs b/device_model/src/interrupt_controller/aarch64/mod.rs index 5ae43fbf1..90867b599 100644 --- a/device_model/src/interrupt_controller/aarch64/mod.rs +++ b/device_model/src/interrupt_controller/aarch64/mod.rs @@ -137,8 +137,11 @@ mod tests { use super::*; use kvm_ioctls::Kvm; - let kvm = Kvm::new().unwrap(); - let vm = Arc::new(kvm.create_vm().unwrap()); + let vm = if let Ok(vm_fd) = Kvm::new().and_then(|kvm| kvm.create_vm()) { + Arc::new(vm_fd) + } else { + return; + }; let gic_conf = GICConfig { version: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3.into(), -- Gitee From c13a164787a8672ce27c86e3b874f91cace8a10d Mon Sep 17 00:00:00 2001 From: Yang Xiaohe Date: Fri, 25 Sep 2020 11:09:41 +0800 Subject: [PATCH 3/5] main/LightMachine: Complete error messages when vm aborts unexpectedly. 1. Remove unnecessary allowance of clippy lint in main.rs 2. Complete error messages if no KVM module exists or no enough permissions. 3. Complete error messages when parsing logger config. Signed-off-by: Yang Xiaohe --- device_model/src/micro_vm/mod.rs | 7 +++++-- src/main.rs | 16 ++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/device_model/src/micro_vm/mod.rs b/device_model/src/micro_vm/mod.rs index 8b5ddf5b2..0f0cbad11 100644 --- a/device_model/src/micro_vm/mod.rs +++ b/device_model/src/micro_vm/mod.rs @@ -204,8 +204,11 @@ impl LightMachine { /// /// * `vm_config` - Represents the configuration for VM. pub fn new(vm_config: VmConfig) -> Result> { - let kvm = Kvm::new()?; - let vm_fd = Arc::new(kvm.create_vm()?); + let kvm = Kvm::new().chain_err(|| "Failed to open /dev/kvm.")?; + let vm_fd = Arc::new( + kvm.create_vm() + .chain_err(|| "KVM: failed to create VM fd failed")?, + ); let sys_mem = AddressSpace::new(Region::init_container_region(u64::max_value()))?; let nr_slots = kvm.get_nr_memslots(); diff --git a/src/main.rs b/src/main.rs index 9fb043d59..fc8078d30 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,14 +45,13 @@ error_chain! { quick_main!(run); -#[allow(clippy::cast_ptr_alignment)] fn run() -> Result<()> { let cmd_args = create_args_parser().get_matches()?; if let Some(logfile_path) = cmd_args.value_of("display log") { if logfile_path.is_empty() { logger::init_logger_with_env(Some(Box::new(std::io::stdout()))) - .expect("logger init failed!"); + .chain_err(|| "Failed to init logger.")?; } else { let logfile = std::fs::OpenOptions::new() .read(false) @@ -60,11 +59,11 @@ fn run() -> Result<()> { .append(true) .create(true) .mode(0o640) - .open(logfile_path)?; - logger::init_logger_with_env(Some(Box::new(logfile))).expect("logger init failed!"); + .open(logfile_path) + .chain_err(|| "Failed to open log file")?; + logger::init_logger_with_env(Some(Box::new(logfile))) + .chain_err(|| "Failed to init logger.")?; } - } else { - logger::init_logger_with_env(None).expect("logger init failed!"); } std::panic::set_hook(Box::new(|panic_msg| { @@ -128,7 +127,8 @@ fn real_main(cmd_args: &arg_parser::ArgMatches) -> Result<()> { MainLoop::update_event(EventNotifierHelper::internal_notifiers(Arc::new( Mutex::new(api_socket), - )))?; + ))) + .chain_err(|| "Failed to add api event to MainLoop")?; vm.realize()?; vm.vm_start( @@ -141,7 +141,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches) -> Result<()> { } loop { - if !MainLoop::run()? { + if !MainLoop::run().chain_err(|| "MainLoop exits unexpectedly: error occurs")? { break; } } -- Gitee From adcb3c2edd2eb17ace7429bc5da9c56bc0677f4f Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Fri, 25 Sep 2020 11:55:57 +0800 Subject: [PATCH 4/5] README/docs: Add Chinese version of README.md and modify README.md and design.md 1. Add Chinese version of README.md 2. Synchronously modify the Chinese and English version of README.md 3. Modify the description of the Features chapter of design.md Signed-off-by: Fei Xu --- README.ch.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 10 +-------- docs/design.md | 2 +- 3 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 README.ch.md diff --git a/README.ch.md b/README.ch.md new file mode 100644 index 000000000..f7f4b5dbc --- /dev/null +++ b/README.ch.md @@ -0,0 +1,57 @@ +# StratoVirt: +StratoVirt是计算产业中面向云数据中心的企业级虚拟化平台,实现了一套架构统一支持虚拟机、容器、Serverless三种场景。StratoVirt在轻量低噪、软硬协同、Rust语言级安全等方面具备关键技术竞争优势。 + +StratoVirt预留了接口和设计来支持更多特性,未来甚至向标准虚拟化演进。 + +## 如何开始 + +### 环境准备 +在编译StratoVirt前,请确保Rust语言环境和Cargo软件已经安装成功。如果没有安装,请参考以下链接的指导进行安装: + +https://www.rust-lang.org/tools/install + +### 编译软件 +为了编译StratoVirt,需要先克隆代码工程,然后执行编译命令,如下: +```sh +$ git clone https://gitee.com/openeuler/stratovirt.git +$ cd stratovirt +$ cargo build --release +``` +可以在`target/release/stratovirt`路径下找到生成的二进制文件 + +### 运行软件 +为了快速上手StratoVirt,需要准备 +* PE格式的Linux内核镜像 +* EXT4格式的rootfs镜像 + +```shell +# 如果-api-channel的socket文件已经存在,请先删除它 +$ ./target/release/stratovirt \ + -kernel /path/to/kernel \ + -append console=ttyS0 root=/dev/vda reboot=k panic=1 \ + -drive file=/path/to/rootfs,id=rootfs,readonly=off \ + -api-channel unix:/path/to/socket \ + -serial stdio +``` + +关于制作rootfs镜像、编译内核镜像以及编译StratoVirt的详细指导,请参考[StratoVirt Quickstart](./docs/quickstart.md)。 + +StratoVirt所支持更多特性,详细指导请参考[Configuration Guidebook](docs/config_guidebook.md)。 + +## 设计 +想获取更多的StratoVirt核心架构设计信息,请参考[StratoVirt design](./docs/design.md)。 + +## 如何贡献 +我们非常欢迎新贡献者的加入,并且非常乐意为新的贡献者提供指导和帮助。 +StratoVirt遵循Rust语言编程规范,请参考以下链接: + +https://github.com/rust-dev-tools/fmt-rfcs/tree/master/guide + +https://github.com/rust-lang/rust-clippy + +如果你想获取更多关于StratoVirt的信息,请参考以下链接: + +https://gitee.com/openeuler/stratovirt/wikis + +## 许可 +StratoVirt使用Mulan PSL v2开源协议许可 diff --git a/README.md b/README.md index 7ac244519..8301d6214 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,5 @@ # StratoVirt -StratoVirt is an opensource VMM(Virtual Machine Manager) which aims to perform -next generation virtualization. - -Based on Rust programming language, StratoVirt is lightweight, efficient and safe. -StratoVirt reduces memory resource consumption and improves VM startup speed while -retains isolation capability and security capability of traditional virtualization. - -StratoVirt supports communicating with external systems using OCI compatible Interface, -and can be applied to microservices or serverless scenarios. +StratoVirt is an enterprise-level virtualization platform for cloud data centers in the computing industry. It implements a set of architecture that supports three scenarios: virtual machines, containers, and serverless. StratoVirt has key technological competitive advantages in light weight and low noise, software and hardware coordination, and Rust language-level security. StratoVirt reserves interface and design for importing more features, even standard virtualization. diff --git a/docs/design.md b/docs/design.md index ae2bb12a3..b686a4bec 100644 --- a/docs/design.md +++ b/docs/design.md @@ -13,7 +13,7 @@ StratoVirt reserves interface and design for importing more features, even stand - Fast cold boot: Benefit from the minimalist design, StratoVirt could boot a microVM in 50ms. - Low memory overhead: StratoVirt works with a memory footprint at 3MB. - IO enhancement: StratoVirt offers normal IO ability with minimalist IO device emulation. -- OCI compatibility: StratoVirt offers OCI-compatible interface,which connects to Kubernetes ecosystem perfectly. +- OCI compatibility: StratoVirt works with isula and kata container, and can be integrated in Kubernetes ecosystem perfectly. - Multi-platform support: Fully support for Intel and Arm platform. - Expansibility: StratoVirt reserves interface and design for importing more features, even expand to standard virtualization support. -- Gitee From 9c467555e55a3ab357a92fd00b8ffa80c52fe9f0 Mon Sep 17 00:00:00 2001 From: Liang Zhang Date: Fri, 25 Sep 2020 09:07:59 +0800 Subject: [PATCH 5/5] micro_vm: add a new syscall mremap kata connected with socket,and send msg. Hotplug and unplug repeatedly may call mremap syscall Signed-off-by: Liang Zhang --- device_model/src/micro_vm/micro_syscall.rs | 9 +++++---- docs/config_guidebook.md | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/device_model/src/micro_vm/micro_syscall.rs b/device_model/src/micro_vm/micro_syscall.rs index 2ea20a5ba..ee8b81656 100644 --- a/device_model/src/micro_vm/micro_syscall.rs +++ b/device_model/src/micro_vm/micro_syscall.rs @@ -52,10 +52,10 @@ const KVM_SET_DEVICE_ATTR: u32 = 0x4018_aee1; /// /// # Notes /// This allowlist limit syscall with: -/// * x86_64-unknown-gnu: 34 syscalls -/// * x86_64-unknown-musl: 33 syscalls -/// * aarch64-unknown-gnu: 33 syscalls -/// * aarch64-unknown-musl: 32 syscalls +/// * x86_64-unknown-gnu: 35 syscalls +/// * x86_64-unknown-musl: 34 syscalls +/// * aarch64-unknown-gnu: 34 syscalls +/// * aarch64-unknown-musl: 33 syscalls /// To reduce performance losses, the syscall rules is ordered by frequency. fn syscall_allow_list() -> Vec { vec![ @@ -76,6 +76,7 @@ fn syscall_allow_list() -> Vec { BpfRule::new(libc::SYS_recvmsg), BpfRule::new(libc::SYS_sendmsg), BpfRule::new(libc::SYS_recvfrom), + BpfRule::new(libc::SYS_mremap), BpfRule::new(libc::SYS_io_setup), BpfRule::new(libc::SYS_brk), BpfRule::new(libc::SYS_fcntl) diff --git a/docs/config_guidebook.md b/docs/config_guidebook.md index 00641e8c0..837969a72 100644 --- a/docs/config_guidebook.md +++ b/docs/config_guidebook.md @@ -469,7 +469,7 @@ And you can also restore StratoVirt's **pid number** to a file by: ### 4.2 Seccomp StratoVirt use [prctl(2)](https://man7.org/linux/man-pages/man2/prctl.2.html) to limit the syscalls -in StratoVirt process by default. StratoVirt use only 32 syscalls in aarch64 (33 syscalls in x86_64) after running. +in StratoVirt process by default. StratoVirt use only 33 syscalls in aarch64 (34 syscalls in x86_64) after running. It will make a slight influence on performance to StratoVirt. If you want to disable seccomp, you can run StratoVirt with `-disable-seccomp`. -- Gitee