Merge pull request #5767 from Megan-Wright/CCv0

CC: Merge main into CCv0 branch
This commit is contained in:
Fabiano Fidêncio
2022-11-30 18:18:45 +01:00
committed by GitHub
47 changed files with 638 additions and 59 deletions

View File

@@ -25,6 +25,7 @@ jobs:
- rootfs-image
- rootfs-initrd
- virtiofsd
- nydus
steps:
- uses: actions/checkout@v2
- name: Install docker

View File

@@ -50,6 +50,7 @@ jobs:
- cloud-hypervisor
- firecracker
- kernel
- nydus
- qemu
- rootfs-image
- rootfs-initrd

View File

@@ -13,6 +13,7 @@ jobs:
- cloud-hypervisor
- firecracker
- kernel
- nydus
- qemu
- rootfs-image
- rootfs-initrd

View File

@@ -81,7 +81,7 @@ Notes: given that the `mountInfo` is persisted to the disk by the Kata runtime,
Instead of the CSI node driver writing the mount info into a `csiPlugin.json` file under the volume root,
as described in the original proposal, here we propose that the CSI node driver passes the mount information to
the Kata Containers runtime through a new `kata-runtime` commandline command. The `kata-runtime` then writes the mount
information to a `mount-info.json` file in a predefined location (`/run/kata-containers/shared/direct-volumes/[volume_path]/`).
information to a `mountInfo.json` file in a predefined location (`/run/kata-containers/shared/direct-volumes/[volume_path]/`).
When the Kata Containers runtime starts a container, it verifies whether a volume mount is a direct-assigned volume by checking
whether there is a `mountInfo` file under the computed Kata `direct-volumes` directory. If it is, the runtime parses the `mountInfo` file,

View File

@@ -545,6 +545,12 @@ Create the hook execution file for Kata:
/usr/bin/nvidia-container-toolkit -debug $@
```
Make sure the hook shell is executable:
```sh
chmod +x $ROOTFS_DIR/usr/share/oci/hooks/prestart/nvidia-container-toolkit.sh
```
As the last step one can do some cleanup of files or package caches. Build the
rootfs and configure it for use with Kata according to the development guide.

1
src/agent/Cargo.lock generated
View File

@@ -2154,6 +2154,7 @@ dependencies = [
"ttrpc",
"url",
"vsock-exporter",
"which",
]
[[package]]

View File

@@ -75,6 +75,7 @@ openssl = { version = "0.10.38", features = ["vendored"] }
[dev-dependencies]
tempfile = "3.1.0"
test-utils = { path = "../libs/test-utils" }
which = "4.3.0"
[workspace]
members = [

View File

@@ -2202,6 +2202,11 @@ mod tests {
use tempfile::{tempdir, TempDir};
use test_utils::{assert_result, skip_if_not_root};
use ttrpc::{r#async::TtrpcContext, MessageHeader};
use which::which;
fn check_command(cmd: &str) -> bool {
which(cmd).is_ok()
}
fn mk_ttrpc_context() -> TtrpcContext {
TtrpcContext {
@@ -2921,6 +2926,18 @@ OtherField:other
async fn test_ip_tables() {
skip_if_not_root!();
if !check_command(IPTABLES_SAVE)
|| !check_command(IPTABLES_RESTORE)
|| !check_command(IP6TABLES_SAVE)
|| !check_command(IP6TABLES_RESTORE)
{
warn!(
sl!(),
"one or more commands for ip tables test are missing, skip it"
);
return;
}
let logger = slog::Logger::root(slog::Discard, o!());
let sandbox = Sandbox::new(&logger).unwrap();
let agent_service = Box::new(AgentService {

View File

@@ -10,6 +10,7 @@ use crate::config::{ConfigOps, TomlConfig};
pub use vendor::AgentVendor;
use super::default::{DEFAULT_AGENT_LOG_PORT, DEFAULT_AGENT_VSOCK_PORT};
use crate::eother;
/// agent name of Kata agent.
pub const AGENT_NAME_KATA: &str = "kata";
@@ -108,6 +109,16 @@ fn default_health_check_timeout() -> u32 {
90_000
}
impl Agent {
fn validate(&self) -> Result<()> {
if self.dial_timeout_ms == 0 {
return Err(eother!("dial_timeout_ms couldn't be 0."));
}
Ok(())
}
}
impl ConfigOps for Agent {
fn adjust_config(conf: &mut TomlConfig) -> Result<()> {
AgentVendor::adjust_config(conf)?;
@@ -116,6 +127,9 @@ impl ConfigOps for Agent {
fn validate(conf: &TomlConfig) -> Result<()> {
AgentVendor::validate(conf)?;
for (_, agent_config) in conf.agent.iter() {
agent_config.validate()?;
}
Ok(())
}
}

View File

@@ -48,6 +48,7 @@ dependencies = [
"kata-types",
"log",
"logging",
"nix 0.24.2",
"oci",
"protobuf",
"protocols",
@@ -1212,6 +1213,7 @@ dependencies = [
"logging",
"nix 0.24.2",
"persist",
"rand 0.8.5",
"seccompiler",
"serde",
"serde_json",

View File

@@ -20,6 +20,7 @@ slog-scope = "4.4.0"
ttrpc = { version = "0.6.1" }
tokio = { version = "1.8.0", features = ["fs", "rt"] }
url = "2.2.2"
nix = "0.24.2"
kata-types = { path = "../../../libs/kata-types"}
logging = { path = "../../../libs/logging"}

View File

@@ -35,8 +35,8 @@ pub enum Stream {
// model, and mediates communication between AF_UNIX sockets (on the host end)
// and AF_VSOCK sockets (on the guest end).
Unix(UnixStream),
// TODO: support vsock
// vsock://<cid>:<port>
Vsock(UnixStream),
}
impl Stream {
@@ -47,7 +47,7 @@ impl Stream {
) -> Poll<std::io::Result<()>> {
// Safety: `UnixStream::read` correctly handles reads into uninitialized memory
match self {
Stream::Unix(stream) => Pin::new(stream).poll_read(cx, buf),
Stream::Unix(stream) | Stream::Vsock(stream) => Pin::new(stream).poll_read(cx, buf),
}
}
}
@@ -55,7 +55,7 @@ impl Stream {
impl IntoRawFd for Stream {
fn into_raw_fd(self) -> RawFd {
match self {
Stream::Unix(stream) => match stream.into_std() {
Stream::Unix(stream) | Stream::Vsock(stream) => match stream.into_std() {
Ok(stream) => stream.into_raw_fd(),
Err(err) => {
error!(sl!(), "failed to into std unix stream {:?}", err);

View File

@@ -4,8 +4,15 @@
// SPDX-License-Identifier: Apache-2.0
//
use anyhow::Result;
use std::{
os::unix::prelude::{AsRawFd, FromRawFd},
time::Duration,
};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use nix::sys::socket::{connect, socket, AddressFamily, SockFlag, SockType, VsockAddr};
use tokio::net::UnixStream;
use super::{ConnectConfig, Sock, Stream};
@@ -26,7 +33,50 @@ impl Vsock {
#[async_trait]
impl Sock for Vsock {
async fn connect(&self, _config: &ConnectConfig) -> Result<Stream> {
todo!()
async fn connect(&self, config: &ConnectConfig) -> Result<Stream> {
let retry_times = config.reconnect_timeout_ms / config.dial_timeout_ms;
let sock_addr = VsockAddr::new(self.vsock_cid, self.port);
let connect_once = || {
// Create socket fd
let socket = socket(
AddressFamily::Vsock,
SockType::Stream,
SockFlag::empty(),
None,
)
.context("failed to create vsock socket")?;
// Wrap the socket fd in a UnixStream, so that it is closed when
// anything fails.
// We MUST NOT reuse a vsock socket which has failed a connection
// attempt before, since a ECONNRESET error marks the whole socket as
// broken and non-reusable.
let socket = unsafe { std::os::unix::net::UnixStream::from_raw_fd(socket) };
// Connect the socket to vsock server.
connect(socket.as_raw_fd(), &sock_addr)
.with_context(|| format!("failed to connect to {}", sock_addr))?;
// Finally, convert the std UnixSocket to tokio's UnixSocket.
UnixStream::from_std(socket).context("from_std")
};
for i in 0..retry_times {
match connect_once() {
Ok(stream) => {
info!(
sl!(),
"connect vsock success on {} current client fd {}",
i,
stream.as_raw_fd()
);
return Ok(Stream::Vsock(stream));
}
Err(_) => {
tokio::time::sleep(Duration::from_millis(config.dial_timeout_ms)).await;
}
}
}
Err(anyhow!("cannot connect to agent ttrpc server {:?}", config))
}
}

View File

@@ -23,6 +23,7 @@ slog-scope = "4.4.0"
thiserror = "1.0"
tokio = { version = "1.8.0", features = ["sync"] }
vmm-sys-util = "0.11.0"
rand = "0.8.4"
kata-sys-util = { path = "../../../libs/kata-sys-util" }
kata-types = { path = "../../../libs/kata-types" }

View File

@@ -15,7 +15,7 @@ pub use vfio::{bind_device_to_host, bind_device_to_vfio, VfioBusMode, VfioConfig
mod share_fs_mount;
pub use share_fs_mount::{ShareFsMountConfig, ShareFsMountType, ShareFsOperation};
mod vsock;
pub use vsock::VsockConfig;
pub use vsock::{HybridVsockConfig, VsockConfig};
use std::fmt;
@@ -27,6 +27,7 @@ pub enum Device {
Vfio(VfioConfig),
ShareFsMount(ShareFsMountConfig),
Vsock(VsockConfig),
HybridVsock(HybridVsockConfig),
}
impl fmt::Display for Device {

View File

@@ -4,8 +4,13 @@
// SPDX-License-Identifier: Apache-2.0
//
use anyhow::{Context, Result};
use rand::Rng;
use std::os::unix::prelude::AsRawFd;
use tokio::fs::{File, OpenOptions};
#[derive(Debug)]
pub struct VsockConfig {
pub struct HybridVsockConfig {
/// Unique identifier of the device
pub id: String,
@@ -15,3 +20,76 @@ pub struct VsockConfig {
/// unix domain socket path
pub uds_path: String,
}
#[derive(Debug)]
pub struct VsockConfig {
/// Unique identifier of the device
pub id: String,
/// A 32-bit Context Identifier (CID) used to identify the guest.
pub guest_cid: u32,
/// Vhost vsock fd. Hold to ensure CID is not used by other VM.
pub vhost_fd: File,
}
const VHOST_VSOCK_DEVICE: &str = "/dev/vhost-vsock";
// From <linux/vhost.h>
// Generate a wrapper function for VHOST_VSOCK_SET_GUEST_CID ioctl.
// It set guest CID for vsock fd, and return error if CID is already
// in use.
const VHOST_VIRTIO_IOCTL: u8 = 0xAF;
const VHOST_VSOCK_SET_GUEST_CID: u8 = 0x60;
nix::ioctl_write_ptr!(
vhost_vsock_set_guest_cid,
VHOST_VIRTIO_IOCTL,
VHOST_VSOCK_SET_GUEST_CID,
u64
);
const CID_RETRY_COUNT: u32 = 50;
impl VsockConfig {
pub async fn new(id: String) -> Result<Self> {
let vhost_fd = OpenOptions::new()
.read(true)
.write(true)
.open(VHOST_VSOCK_DEVICE)
.await
.context(format!(
"failed to open {}, try to run modprobe vhost_vsock.",
VHOST_VSOCK_DEVICE
))?;
let mut rng = rand::thread_rng();
// Try 50 times to find a context ID that is not in use.
for _ in 0..CID_RETRY_COUNT {
// First usable CID above VMADDR_CID_HOST (see vsock(7))
let first_usable_cid = 3;
let rand_cid = rng.gen_range(first_usable_cid..=(u32::MAX));
let guest_cid =
unsafe { vhost_vsock_set_guest_cid(vhost_fd.as_raw_fd(), &(rand_cid as u64)) };
match guest_cid {
Ok(_) => {
return Ok(VsockConfig {
id,
guest_cid: rand_cid,
vhost_fd,
});
}
Err(nix::Error::EADDRINUSE) => {
// The CID is already in use. Try another one.
}
Err(err) => {
return Err(err).context("failed to set guest CID");
}
}
}
anyhow::bail!(
"failed to find a free vsock context ID after {} attempts",
CID_RETRY_COUNT
);
}
}

View File

@@ -15,8 +15,8 @@ use dragonball::api::v1::{
use super::DragonballInner;
use crate::{
device::Device, NetworkConfig, ShareFsDeviceConfig, ShareFsMountConfig, ShareFsMountType,
ShareFsOperation, VmmState, VsockConfig,
device::Device, HybridVsockConfig, NetworkConfig, ShareFsDeviceConfig, ShareFsMountConfig,
ShareFsMountType, ShareFsOperation, VmmState,
};
const MB_TO_B: u32 = 1024 * 1024;
@@ -56,13 +56,16 @@ impl DragonballInner {
config.no_drop,
)
.context("add block device"),
Device::Vsock(config) => self.add_vsock(&config).context("add vsock"),
Device::HybridVsock(config) => self.add_hvsock(&config).context("add vsock"),
Device::ShareFsDevice(config) => self
.add_share_fs_device(&config)
.context("add share fs device"),
Device::ShareFsMount(config) => self
.add_share_fs_mount(&config)
.context("add share fs mount"),
Device::Vsock(_) => {
todo!()
}
}
}
@@ -139,7 +142,7 @@ impl DragonballInner {
.context("insert network device")
}
fn add_vsock(&mut self, config: &VsockConfig) -> Result<()> {
fn add_hvsock(&mut self, config: &HybridVsockConfig) -> Result<()> {
let vsock_cfg = VsockDeviceConfigInfo {
id: String::from("root"),
guest_cid: config.guest_cid,

View File

@@ -32,7 +32,7 @@ impl DragonballInner {
// prepare vsock
let uds_path = [&self.jailer_root, DEFAULT_HYBRID_VSOCK_NAME].join("/");
let d = crate::device::Device::Vsock(crate::device::VsockConfig {
let d = crate::device::Device::HybridVsock(crate::device::HybridVsockConfig {
id: format!("vsock-{}", &self.id),
guest_cid: 3,
uds_path,

View File

@@ -4,17 +4,18 @@
// SPDX-License-Identifier: Apache-2.0
//
use std::sync::Arc;
use std::{sync::Arc, thread};
use crate::resource_persist::ResourceState;
use agent::{Agent, Storage};
use anyhow::{Context, Result};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use hypervisor::Hypervisor;
use kata_types::config::TomlConfig;
use kata_types::mount::Mount;
use oci::LinuxResources;
use persist::sandbox_persist::Persist;
use tokio::runtime;
use crate::{
cgroups::{CgroupArgs, CgroupsResource},
@@ -88,11 +89,32 @@ impl ResourceManagerInner {
};
}
ResourceConfig::Network(c) => {
let d = network::new(&c).await.context("new network")?;
d.setup(self.hypervisor.as_ref())
.await
.context("setup network")?;
self.network = Some(d)
// 1. When using Rust asynchronous programming, we use .await to
// allow other task to run instead of waiting for the completion of the current task.
// 2. Also, when handling the pod network, we need to set the shim threads
// into the network namespace to perform those operations.
// However, as the increase of the I/O intensive tasks, two issues could be caused by the two points above:
// a. When the future is blocked, the current thread (which is in the pod netns)
// might be take over by other tasks. After the future is finished, the thread take over
// the current task might not be in the pod netns. But the current task still need to run in pod netns
// b. When finish setting up the network, the current thread will be set back to the host namespace.
// In Rust Async, if the current thread is taken over by other task, the netns is dropped on another thread,
// but it is not in netns. So, the previous thread would still remain in the pod netns.
// The solution is to block the future on the current thread, it is enabled by spawn an os thread, create a
// tokio runtime, and block the task on it.
let hypervisor = self.hypervisor.clone();
let network = thread::spawn(move || -> Result<Arc<dyn Network>> {
let rt = runtime::Builder::new_current_thread().enable_io().build()?;
let d = rt.block_on(network::new(&c)).context("new network")?;
rt.block_on(d.setup(hypervisor.as_ref()))
.context("setup network")?;
Ok(d)
})
.join()
.map_err(|e| anyhow!("{:?}", e))
.context("Couldn't join on the associated thread")?
.context("failed to set up network")?;
self.network = Some(network);
}
};
}

View File

@@ -20,11 +20,12 @@ use kata_types::{annotations::Annotation, config::TomlConfig};
use linux_container::LinuxContainer;
use persist::sandbox_persist::Persist;
use tokio::sync::{mpsc::Sender, RwLock};
use virt_container::sandbox::SandboxRestoreArgs;
use virt_container::sandbox::VirtSandbox;
use virt_container::sandbox_persist::{SandboxState, SandboxTYPE};
#[cfg(feature = "virt")]
use virt_container::VirtContainer;
use virt_container::{
sandbox::{SandboxRestoreArgs, VirtSandbox},
sandbox_persist::SandboxState,
VirtContainer,
};
#[cfg(feature = "wasm")]
use wasm_container::WasmContainer;
@@ -153,8 +154,19 @@ impl RuntimeHandlerManager {
toml_config: TomlConfig::default(),
sender,
};
match sandbox_state.sandbox_type {
SandboxTYPE::VIRTCONTAINER => {
match sandbox_state.sandbox_type.clone() {
#[cfg(feature = "linux")]
name if name == LinuxContainer::name() => {
// TODO :support linux container (https://github.com/kata-containers/kata-containers/issues/4905)
return Ok(());
}
#[cfg(feature = "wasm")]
name if name == WasmContainer::name() => {
// TODO :support wasm container (https://github.com/kata-containers/kata-containers/issues/4906)
return Ok(());
}
#[cfg(feature = "virt")]
name if name == VirtContainer::name() => {
let sandbox = VirtSandbox::restore(sandbox_args, sandbox_state)
.await
.context("failed to restore the sandbox")?;
@@ -163,12 +175,7 @@ impl RuntimeHandlerManager {
.await
.context("failed to cleanup the resource")?;
}
SandboxTYPE::LINUXCONTAINER => {
// TODO :support linux container (https://github.com/kata-containers/kata-containers/issues/4905)
return Ok(());
}
SandboxTYPE::WASMCONTAINER => {
// TODO :support wasm container (https://github.com/kata-containers/kata-containers/issues/4906)
_ => {
return Ok(());
}
}

View File

@@ -23,6 +23,7 @@ use common::{message::Message, RuntimeHandler, RuntimeInstance};
use hypervisor::{dragonball::Dragonball, Hypervisor, HYPERVISOR_DRAGONBALL};
use kata_types::config::{hypervisor::register_hypervisor_plugin, DragonballConfig, TomlConfig};
use resource::ResourceManager;
use sandbox::VIRTCONTAINER;
use tokio::sync::mpsc::Sender;
unsafe impl Send for VirtContainer {}
@@ -39,7 +40,7 @@ impl RuntimeHandler for VirtContainer {
}
fn name() -> String {
"virt_container".to_string()
VIRTCONTAINER.to_string()
}
fn new_handler() -> Arc<dyn RuntimeHandler> {

View File

@@ -28,8 +28,10 @@ use resource::{
};
use tokio::sync::{mpsc::Sender, Mutex, RwLock};
use crate::{health_check::HealthCheck, sandbox_persist::SandboxTYPE};
use crate::health_check::HealthCheck;
use persist::{self, sandbox_persist::Persist};
pub(crate) const VIRTCONTAINER: &str = "virt_container";
pub struct SandboxRestoreArgs {
pub sid: String,
pub toml_config: TomlConfig,
@@ -303,7 +305,7 @@ impl Persist for VirtSandbox {
/// Save a state of Sandbox
async fn save(&self) -> Result<Self::State> {
let sandbox_state = crate::sandbox_persist::SandboxState {
sandbox_type: SandboxTYPE::VIRTCONTAINER,
sandbox_type: VIRTCONTAINER.to_string(),
resource: Some(self.resource_manager.save().await?),
hypervisor: Some(self.hypervisor.save_state().await?),
};

View File

@@ -8,16 +8,9 @@ use hypervisor::hypervisor_persist::HypervisorState;
use resource::resource_persist::ResourceState;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub enum SandboxTYPE {
VIRTCONTAINER,
LINUXCONTAINER,
WASMCONTAINER,
}
#[derive(Serialize, Deserialize)]
pub struct SandboxState {
pub sandbox_type: SandboxTYPE,
pub sandbox_type: String,
pub resource: Option<ResourceState>,
pub hypervisor: Option<HypervisorState>,
}

View File

@@ -216,6 +216,7 @@ DEFVALIDVIRTIOFSDAEMONPATHS := [\"$(DEFVIRTIOFSDAEMON)\"]
#if value is 0, DAX is not enabled
DEFVIRTIOFSCACHESIZE ?= 0
DEFVIRTIOFSCACHE ?= auto
DEFVIRTIOFSQUEUESIZE ?= 1024
# Format example:
# [\"-o\", \"arg1=xxx,arg2\", \"-o\", \"hello world\", \"--arg3=yyy\"]
#
@@ -592,6 +593,7 @@ USER_VARS += DEFVIRTIOFSDAEMON
USER_VARS += DEFVALIDVIRTIOFSDAEMONPATHS
USER_VARS += DEFVIRTIOFSCACHESIZE
USER_VARS += DEFVIRTIOFSCACHE
USER_VARS += DEFVIRTIOFSQUEUESIZE
USER_VARS += DEFVIRTIOFSEXTRAARGS
USER_VARS += DEFENABLEANNOTATIONS
USER_VARS += DEFENABLEIOTHREADS

View File

@@ -126,6 +126,9 @@ valid_virtio_fs_daemon_paths = @DEFVALIDVIRTIOFSDAEMONPATHS@
# Default size of DAX cache in MiB
virtio_fs_cache_size = @DEFVIRTIOFSCACHESIZE@
# Default size of virtqueues
virtio_fs_queue_size = @DEFVIRTIOFSQUEUESIZE@
# Extra args for virtiofsd daemon
#
# Format example:

View File

@@ -215,6 +215,9 @@ valid_virtio_fs_daemon_paths = @DEFVALIDVIRTIOFSDAEMONPATHS@
# Default size of DAX cache in MiB
virtio_fs_cache_size = @DEFVIRTIOFSCACHESIZE@
# Default size of virtqueues
virtio_fs_queue_size = @DEFVIRTIOFSQUEUESIZE@
# Extra args for virtiofsd daemon
#
# Format example:

View File

@@ -9,7 +9,7 @@ require (
github.com/blang/semver/v4 v4.0.0
github.com/containerd/cgroups v1.0.5-0.20220625035431-cf7417bca682
github.com/containerd/console v1.0.3
github.com/containerd/containerd v1.6.6
github.com/containerd/containerd v1.6.8
github.com/containerd/cri-containerd v1.19.0
github.com/containerd/fifo v1.0.0
github.com/containerd/ttrpc v1.1.0

View File

@@ -318,6 +318,8 @@ type VhostUserDeviceAttrs struct {
Index int
CacheSize uint32
QueueSize uint32
}
// GetHostPathFunc is function pointer used to mock GetHostPath in tests.

View File

@@ -1362,6 +1362,7 @@ type VhostUserDevice struct {
Address string //used for MAC address in net case
Tag string //virtio-fs volume id for mounting inside guest
CacheSize uint32 //virtio-fs DAX cache size in MiB
QueueSize uint32 //size of virtqueues
SharedVersions bool //enable virtio-fs shared version metadata
VhostUserType DeviceDriver
@@ -1529,6 +1530,11 @@ func (vhostuserDev VhostUserDevice) QemuFSParams(config *Config) []string {
deviceParams = append(deviceParams, driver)
deviceParams = append(deviceParams, fmt.Sprintf("chardev=%s", vhostuserDev.CharDevID))
deviceParams = append(deviceParams, fmt.Sprintf("tag=%s", vhostuserDev.Tag))
queueSize := uint32(1024)
if vhostuserDev.QueueSize != 0 {
queueSize = vhostuserDev.QueueSize
}
deviceParams = append(deviceParams, fmt.Sprintf("queue-size=%d", queueSize))
if vhostuserDev.CacheSize != 0 {
deviceParams = append(deviceParams, fmt.Sprintf("cache-size=%dM", vhostuserDev.CacheSize))
}
@@ -2725,9 +2731,14 @@ func (config *Config) appendQMPSockets() {
}
}
func (config *Config) appendDevices() {
func (config *Config) appendDevices(logger QMPLog) {
if logger == nil {
logger = qmpNullLogger{}
}
for _, d := range config.Devices {
if !d.Valid() {
logger.Errorf("vm device is not valid: %+v", config.Devices)
continue
}
@@ -3002,7 +3013,7 @@ func LaunchQemu(config Config, logger QMPLog) (string, error) {
config.appendCPUModel()
config.appendQMPSockets()
config.appendMemory()
config.appendDevices()
config.appendDevices(logger)
config.appendRTC()
config.appendGlobalParam()
config.appendPFlashParam()

View File

@@ -34,7 +34,7 @@ func testConfigAppend(config *Config, structure interface{}, expected string, t
case Device:
config.Devices = []Device{s}
config.appendDevices()
config.appendDevices(nil)
case Knobs:
config.Knobs = s
@@ -889,7 +889,7 @@ func TestBadQMPSockets(t *testing.T) {
func TestBadDevices(t *testing.T) {
c := &Config{}
c.appendDevices()
c.appendDevices(nil)
if len(c.qemuParams) != 0 {
t.Errorf("Expected empty qemuParams, found %s", c.qemuParams)
}
@@ -941,7 +941,7 @@ func TestBadDevices(t *testing.T) {
},
}
c.appendDevices()
c.appendDevices(nil)
if len(c.qemuParams) != 0 {
t.Errorf("Expected empty qemuParams, found %s", c.qemuParams)
}

View File

@@ -120,6 +120,7 @@ type hypervisor struct {
RxRateLimiterMaxRate uint64 `toml:"rx_rate_limiter_max_rate"`
TxRateLimiterMaxRate uint64 `toml:"tx_rate_limiter_max_rate"`
MemOffset uint64 `toml:"memory_offset"`
DefaultMaxMemorySize uint64 `toml:"default_maxmemory"`
DiskRateLimiterBwMaxRate int64 `toml:"disk_rate_limiter_bw_max_rate"`
DiskRateLimiterBwOneTimeBurst int64 `toml:"disk_rate_limiter_bw_one_time_burst"`
DiskRateLimiterOpsMaxRate int64 `toml:"disk_rate_limiter_ops_max_rate"`
@@ -129,10 +130,10 @@ type hypervisor struct {
NetRateLimiterOpsMaxRate int64 `toml:"net_rate_limiter_ops_max_rate"`
NetRateLimiterOpsOneTimeBurst int64 `toml:"net_rate_limiter_ops_one_time_burst"`
VirtioFSCacheSize uint32 `toml:"virtio_fs_cache_size"`
VirtioFSQueueSize uint32 `toml:"virtio_fs_queue_size"`
DefaultMaxVCPUs uint32 `toml:"default_maxvcpus"`
MemorySize uint32 `toml:"default_memory"`
MemSlots uint32 `toml:"memory_slots"`
DefaultMaxMemorySize uint64 `toml:"default_maxmemory"`
DefaultBridges uint32 `toml:"default_bridges"`
Msize9p uint32 `toml:"msize_9p"`
PCIeRootPort uint32 `toml:"pcie_root_port"`
@@ -808,6 +809,7 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
VirtioFSDaemonList: h.VirtioFSDaemonList,
VirtioFSCacheSize: h.VirtioFSCacheSize,
VirtioFSCache: h.defaultVirtioFSCache(),
VirtioFSQueueSize: h.VirtioFSQueueSize,
VirtioFSExtraArgs: h.VirtioFSExtraArgs,
MemPrealloc: h.MemPrealloc,
HugePages: h.HugePages,

View File

@@ -73,7 +73,7 @@ github.com/containerd/cgroups/v2/stats
# github.com/containerd/console v1.0.3
## explicit; go 1.13
github.com/containerd/console
# github.com/containerd/containerd v1.6.6 => github.com/confidential-containers/containerd v1.6.7-0.20221123142530-25f68aa818ec
# github.com/containerd/containerd v1.6.8 => github.com/confidential-containers/containerd v1.6.7-0.20221123142530-25f68aa818ec
## explicit; go 1.17
github.com/containerd/containerd/api/events
github.com/containerd/containerd/api/services/ttrpc/events/v1

View File

@@ -1610,6 +1610,9 @@ func (clh *cloudHypervisor) addVolume(volume types.Volume) error {
// default values defined by cloud-hypervisor
numQueues := int32(1)
queueSize := int32(1024)
if clh.config.VirtioFSQueueSize != 0 {
queueSize = int32(clh.config.VirtioFSQueueSize)
}
fs := chclient.NewFsConfig(volume.MountTag, vfsdSockPath, numQueues, queueSize)
clh.vmconfig.Fs = &[]chclient.FsConfig{*fs}

View File

@@ -323,6 +323,7 @@ type HypervisorConfig struct {
Msize9p uint32
MemSlots uint32
VirtioFSCacheSize uint32
VirtioFSQueueSize uint32
Uid uint32
Gid uint32
SEVGuestPolicy uint32

View File

@@ -167,6 +167,7 @@ func (nd *nydusd) args() ([]string, error) {
logLevel = "debug"
}
args := []string{
"virtiofs", "--hybrid-mode",
"--log-level", logLevel,
"--apisock", nd.apiSockPath,
"--sock", nd.sockPath,

View File

@@ -99,13 +99,13 @@ func TestNydusdArgs(t *testing.T) {
apiSockPath: "/var/lib/api.sock",
debug: true,
}
expected := "--log-level debug --apisock /var/lib/api.sock --sock /var/lib/vhost-user.sock"
expected := "virtiofs --hybrid-mode --log-level debug --apisock /var/lib/api.sock --sock /var/lib/vhost-user.sock"
args, err := nd.args()
assert.NoError(err)
assert.Equal(expected, strings.Join(args, " "))
nd.debug = false
expected = "--log-level info --apisock /var/lib/api.sock --sock /var/lib/vhost-user.sock"
expected = "virtiofs --hybrid-mode --log-level info --apisock /var/lib/api.sock --sock /var/lib/vhost-user.sock"
args, err = nd.args()
assert.NoError(err)
assert.Equal(expected, strings.Join(args, " "))

View File

@@ -2151,6 +2151,7 @@ func (q *qemu) AddDevice(ctx context.Context, devInfo interface{}, devType Devic
Type: config.VhostUserFS,
CacheSize: q.config.VirtioFSCacheSize,
Cache: q.config.VirtioFSCache,
QueueSize: q.config.VirtioFSQueueSize,
}
vhostDev.SocketPath = sockPath
vhostDev.DevID = id

View File

@@ -696,6 +696,7 @@ func (q *qemuArchBase) appendVhostUserDevice(ctx context.Context, devices []govm
qemuVhostUserDevice.TypeDevID = utils.MakeNameID("fs", attr.DevID, maxDevIDSize)
qemuVhostUserDevice.Tag = attr.Tag
qemuVhostUserDevice.CacheSize = attr.CacheSize
qemuVhostUserDevice.QueueSize = attr.QueueSize
qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserFS
}

View File

@@ -100,6 +100,22 @@ dependencies = [
"os_str_bytes",
]
[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "encoding_rs"
version = "0.8.31"
@@ -109,12 +125,36 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "fastrand"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
dependencies = [
"instant",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.1.0"
@@ -283,6 +323,19 @@ dependencies = [
"tokio-rustls",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]]
name = "idna"
version = "0.3.0"
@@ -303,6 +356,15 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "ipnet"
version = "2.5.0"
@@ -335,9 +397,16 @@ dependencies = [
"reqwest",
"semver",
"serde_json",
"tempfile",
"thiserror",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.135"
@@ -386,6 +455,24 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "native-tls"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "nix"
version = "0.24.2"
@@ -428,6 +515,51 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
[[package]]
name = "openssl"
version = "0.10.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a"
dependencies = [
"autocfg",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "os_str_bytes"
version = "6.3.0"
@@ -452,6 +584,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
name = "privdrop"
version = "0.5.2"
@@ -504,6 +642,24 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "reqwest"
version = "0.11.12"
@@ -520,10 +676,12 @@ dependencies = [
"http-body",
"hyper",
"hyper-rustls",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
@@ -533,6 +691,7 @@ dependencies = [
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
"tokio-rustls",
"tower-service",
"url",
@@ -585,6 +744,16 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "schannel"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
dependencies = [
"lazy_static",
"windows-sys",
]
[[package]]
name = "sct"
version = "0.7.0"
@@ -595,6 +764,29 @@ dependencies = [
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "semver"
version = "1.0.14"
@@ -672,6 +864,20 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.3"
@@ -739,6 +945,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.23.4"
@@ -834,6 +1050,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"

View File

@@ -28,3 +28,4 @@ reqwest = { version = "0.11", default-features = false, features = ["json", "blo
[dev-dependencies]
semver = "1.0.12"
tempfile = "3.1.0"

View File

@@ -5,7 +5,8 @@
#![allow(dead_code)]
use anyhow::{anyhow, Result};
use anyhow::{anyhow, Context, Result};
use std::fs;
const NON_PRIV_USER: &str = "nobody";
@@ -21,13 +22,73 @@ pub fn drop_privs() -> Result<()> {
Ok(())
}
const PROC_VERSION_FILE: &str = "/proc/version";
pub fn get_kernel_version(proc_version_file: &str) -> Result<String> {
let contents = fs::read_to_string(proc_version_file)
.context(format!("Failed to read file {}", proc_version_file))?;
let fields: Vec<&str> = contents.split_whitespace().collect();
if fields.len() < 3 {
return Err(anyhow!("unexpected contents in file {}", proc_version_file));
}
let kernel_version = String::from(fields[2]);
Ok(kernel_version)
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
use tempfile::tempdir;
#[test]
fn test_drop_privs() {
let res = drop_privs();
assert!(res.is_ok());
}
#[test]
fn test_kernel_version_empty_input() {
let res = get_kernel_version("").unwrap_err().to_string();
let err_msg = format!("Failed to read file {}", "");
assert_eq!(res, err_msg);
}
#[test]
fn test_kernel_version_valid_input() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("proc-version");
let path = file_path.clone();
let mut file = fs::File::create(file_path).unwrap();
writeln!(
file,
"Linux version 5.15.0-75-generic (buildd@lcy02-amd64-045)"
)
.unwrap();
let kernel = get_kernel_version(path.to_str().unwrap()).unwrap();
assert_eq!(kernel, "5.15.0-75-generic");
}
#[test]
fn test_kernel_version_system_input() {
let res = get_kernel_version(PROC_VERSION_FILE);
assert!(res.is_ok());
}
#[test]
fn test_kernel_version_invalid_input() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("proc-version");
let path = file_path.clone();
let mut file = fs::File::create(file_path).unwrap();
writeln!(file, "Linux-version-5.15.0-75-generic").unwrap();
let actual = get_kernel_version(path.to_str().unwrap())
.unwrap_err()
.to_string();
let expected = format!("unexpected contents in file {}", path.to_str().unwrap());
assert_eq!(actual, expected);
}
}

View File

@@ -24,6 +24,7 @@ all-parallel: $(MK_DIR)/dockerbuild/install_yq.sh
all: serial-targets \
firecracker-tarball \
kernel-tarball \
nydus-tarball \
qemu-tarball \
shim-v2-tarball \
virtiofsd-tarball
@@ -49,6 +50,8 @@ kernel-tarball:
kernel-experimental-tarball:
${MAKE} $@-build
nydus-tarball:
${MAKE} $@-build
qemu-tarball:
${MAKE} $@-build

View File

@@ -30,6 +30,7 @@ readonly qemu_builder="${static_build_dir}/qemu/build-static-qemu.sh"
readonly shimv2_builder="${static_build_dir}/shim-v2/build.sh"
readonly td_shim_builder="${static_build_dir}/td-shim/build.sh"
readonly virtiofsd_builder="${static_build_dir}/virtiofsd/build.sh"
readonly nydus_builder="${static_build_dir}/nydus/build.sh"
readonly rootfs_builder="${repo_root_dir}/tools/packaging/guest-image/build_image.sh"
@@ -79,6 +80,7 @@ options:
firecracker
kernel
kernel-experimental
nydus
qemu
rootfs-image
rootfs-initrd
@@ -317,6 +319,17 @@ install_virtiofsd() {
sudo install -D --owner root --group root --mode 0744 virtiofsd/virtiofsd "${destdir}/opt/kata/libexec/virtiofsd"
}
# Install static nydus asset
install_nydus() {
info "build static nydus"
"${nydus_builder}"
info "Install static nydus"
mkdir -p "${destdir}/opt/kata/libexec/"
ls -tl . || true
ls -tl nydus-static || true
sudo install -D --owner root --group root --mode 0744 nydus-static/nydusd "${destdir}/opt/kata/libexec/nydusd"
}
#Install all components that are not assets
install_shimv2() {
GO_VERSION="$(yq r ${versions_yaml} languages.golang.meta.newest-version)"
@@ -343,6 +356,7 @@ handle_build() {
install_image
install_initrd
install_kernel
install_nydus
install_qemu
install_shimv2
install_virtiofsd
@@ -394,6 +408,8 @@ handle_build() {
kernel) install_kernel ;;
nydus) install_nydus ;;
kernel-experimental) install_experimental_kernel;;
qemu) install_qemu ;;
@@ -442,6 +458,7 @@ main() {
firecracker
kernel
kernel-experimental
nydus
qemu
rootfs-image
rootfs-initrd

View File

@@ -14,3 +14,4 @@ CONFIG_MANDATORY_FILE_LOCKING
CONFIG_ARM64_UAO
CONFIG_VFIO_MDEV_DEVICE
CONFIG_SPECULATION_MITIGATIONS
CONFIG_X86_SGX

View File

@@ -20,9 +20,9 @@ firecracker_version="${firecracker_version:-}"
if [ -z "$firecracker_repo" ]; then
info "Get firecracker information from runtime versions.yaml"
firecracker_url=$(get_from_kata_deps "assets.hypervisor.firecracker.url")
firecracker_url=$(get_from_kata_deps "assets.hypervisor.firecracker.url")
[ -n "$firecracker_url" ] || die "failed to get firecracker url"
firecracker_repo="${firecracker_url}.git"
firecracker_repo="${firecracker_url}.git"
fi
[ -n "$firecracker_repo" ] || die "failed to get firecracker repo"

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
#
# Copyright (c) 2022 Ant Group
#
# SPDX-License-Identifier: Apache-2.0
set -o errexit
set -o nounset
set -o pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${script_dir}/../../scripts/lib.sh"
ARCH=${ARCH:-$(arch_to_golang "$(uname -m)")}
nydus_url="${nydus_url:-}"
nydus_version="${nydus_version:-}"
info "Get nydus information from runtime versions.yaml"
[ -n "$nydus_url" ] || nydus_url=$(get_from_kata_deps "externals.nydus.url")
[ -n "$nydus_url" ] || die "failed to get nydus url"
[ -n "$nydus_version" ] || nydus_version=$(get_from_kata_deps "externals.nydus.version")
[ -n "$nydus_version" ] || die "failed to get nydus version"
nydus_tarball_url="${nydus_url}/releases/download"
file_name="nydus-static-${nydus_version}-linux-${ARCH}.tgz"
download_url="${nydus_tarball_url}/${nydus_version}/${file_name}"
info "Download nydus version: ${nydus_version} from ${download_url}"
curl -o ${file_name} -L $download_url
sha256sum="${file_name}.sha256sum"
sha256sum_url="${nydus_tarball_url}/${nydus_version}/${sha256sum}"
info "Download nydus ${sha256sum} from ${sha256sum_url}"
curl -o ${sha256sum} -L $sha256sum_url
sha256sum -c ${sha256sum}
tar zxvf ${file_name}

View File

@@ -277,12 +277,12 @@ externals:
nydus:
description: "Nydus image acceleration service"
url: "https://github.com/dragonflyoss/image-service"
version: "v2.1.0-alpha.4"
version: "v2.1.1"
nydus-snapshotter:
description: "Snapshotter for Nydus image acceleration service"
url: "https://github.com/containerd/nydus-snapshotter"
version: "v0.2.3"
version: "v0.3.3"
ovmf:
description: "Firmware, implementation of UEFI for virtual machines."