diff --git a/.github/workflows/release-oci.yaml b/.github/workflows/release-oci.yaml
index 24dbdfa..7966514 100644
--- a/.github/workflows/release-oci.yaml
+++ b/.github/workflows/release-oci.yaml
@@ -4,7 +4,6 @@ on:
push:
branches:
- master
- - feat/container
tags:
- '*'
paths-ignore:
@@ -74,8 +73,8 @@ jobs:
with:
path: |
target/kernel/
- key: ${{ runner.os }}-kernel-${{ hashFiles('/hack/kernel/**') }}
- restore-keys: ${{ runner.os }}-kernel-
+ key: ${{ runner.os }}-kernel-${{ hashFiles('hack/kernel/**') }}
+ restore-keys: ${{ runner.os }}-kernel-${{ hashFiles('hack/kernel/**') }}
- name: Build Kernel
run: make kernel
diff --git a/Cargo.lock b/Cargo.lock
index c3fede4..1dc3886 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-version = 3
+version = 4
[[package]]
name = "acpi_tables"
diff --git a/Makefile b/Makefile
index 80456e4..b488731 100644
--- a/Makefile
+++ b/Makefile
@@ -20,5 +20,5 @@ test: clippy
include hack/hack.mk
-feos_client:
- cd client && cargo build
+cli:
+ cargo build --bin feos-cli
diff --git a/hack/initramfs/make.mk b/hack/initramfs/make.mk
index 15590b7..cf42507 100644
--- a/hack/initramfs/make.mk
+++ b/hack/initramfs/make.mk
@@ -2,8 +2,10 @@ initramfs: target/cloud-hypervisor target/cloud-hypervisor-firmware container-re
mkdir -p target/rootfs/bin
mkdir -p target/rootfs/etc/feos
mkdir -p target/rootfs/usr/share/cloud-hypervisor
+ mkdir -p target/rootfs/usr/share/feos
cp target/cloud-hypervisor/target/cloud-hypervisor-static target/rootfs/bin/cloud-hypervisor
cp target/cloud-hypervisor/target/hypervisor-fw target/rootfs/usr/share/cloud-hypervisor
+ cp target/kernel/vmlinuz target/rootfs/usr/share/feos/vmlinuz
cp target/x86_64-unknown-linux-musl/release/feos target/rootfs/bin/feos
sudo chown -R `whoami` target/rootfs/etc/feos/
cd target/rootfs && rm -f init && ln -s bin/feos init
diff --git a/hack/initramfs/mk-initramfs b/hack/initramfs/mk-initramfs
index 4057ab1..635db9f 100755
--- a/hack/initramfs/mk-initramfs
+++ b/hack/initramfs/mk-initramfs
@@ -35,6 +35,10 @@ echo "Install libraries for FeOS (copy from host)"
install_libs $ROOTFS_DIR/bin/feos
cp -ra /etc/ssl/certs usr/local/ssl/
+echo "Create initramfs (non-compressed)"
+find . -print0 | cpio --create --format=newc --null > "${TARGET_DIR}/initramfs"
+mv "${TARGET_DIR}/initramfs" "${ROOTFS_DIR}/usr/share/feos/"
+
echo "Create initramfs.zst"
find . -print0 | cpio --create --format=newc --null | zstd -3 > "${TARGET_DIR}/initramfs.zst"
diff --git a/hack/kernel/config/feos-linux-6.6.60.config b/hack/kernel/config/feos-linux-6.6.60.config
index 30bf9c7..f5b106f 100644
--- a/hack/kernel/config/feos-linux-6.6.60.config
+++ b/hack/kernel/config/feos-linux-6.6.60.config
@@ -172,21 +172,21 @@ CONFIG_CC_NO_ARRAY_BOUNDS=y
CONFIG_ARCH_SUPPORTS_INT128=y
# CONFIG_NUMA_BALANCING is not set
CONFIG_CGROUPS=y
+CONFIG_MEMCG=y
# CONFIG_CGROUP_FAVOR_DYNMODS is not set
-# CONFIG_MEMCG is not set
# CONFIG_BLK_CGROUP is not set
CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
# CONFIG_CFS_BANDWIDTH is not set
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_SCHED_MM_CID=y
-# CONFIG_CGROUP_PIDS is not set
+CONFIG_CGROUP_PIDS=y
# CONFIG_CGROUP_RDMA is not set
CONFIG_CGROUP_FREEZER=y
# CONFIG_CGROUP_HUGETLB is not set
CONFIG_CPUSETS=y
CONFIG_PROC_PID_CPUSET=y
-# CONFIG_CGROUP_DEVICE is not set
+CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
# CONFIG_CGROUP_PERF is not set
# CONFIG_CGROUP_MISC is not set
@@ -1544,8 +1544,8 @@ CONFIG_NET_CORE=y
# CONFIG_AMT is not set
# CONFIG_MACSEC is not set
# CONFIG_NETCONSOLE is not set
-# CONFIG_TUN is not set
# CONFIG_TUN_VNET_CROSS_LE is not set
+CONFIG_TUN=y
CONFIG_VETH=y
CONFIG_VIRTIO_NET=y
CONFIG_NLMON=y
@@ -3091,7 +3091,7 @@ CONFIG_QFMT_V2=y
CONFIG_QUOTACTL=y
CONFIG_AUTOFS_FS=y
# CONFIG_FUSE_FS is not set
-# CONFIG_OVERLAY_FS is not set
+CONFIG_OVERLAY_FS=y
#
# Caches
diff --git a/hack/libvirt/libvirt-kvm.xml b/hack/libvirt/libvirt-kvm.xml
index beb513c..3c6cc78 100644
--- a/hack/libvirt/libvirt-kvm.xml
+++ b/hack/libvirt/libvirt-kvm.xml
@@ -5,7 +5,7 @@
- 2048
+ 8048
4
hvm
@@ -17,7 +17,7 @@
-
+
diff --git a/proto/feos.proto b/proto/feos.proto
index 28565cb..3df8009 100644
--- a/proto/feos.proto
+++ b/proto/feos.proto
@@ -2,24 +2,30 @@ syntax = "proto3";
package feos_grpc;
service FeosGrpc {
- rpc Reboot (RebootRequest) returns (RebootResponse);
- rpc Shutdown (ShutdownRequest) returns (ShutdownResponse);
- rpc HostInfo (HostInfoRequest) returns (HostInfoResponse);
+ rpc Reboot (RebootRequest) returns (RebootResponse);
+ rpc Shutdown (ShutdownRequest) returns (ShutdownResponse);
+ rpc HostInfo (HostInfoRequest) returns (HostInfoResponse);
- rpc Ping (Empty) returns (Empty);
-
- rpc FetchImage (FetchImageRequest) returns (FetchImageResponse);
+ rpc Ping (Empty) returns (Empty);
- rpc CreateVM (CreateVMRequest) returns (CreateVMResponse);
- rpc GetVM (GetVMRequest) returns (GetVMResponse);
- rpc BootVM (BootVMRequest) returns (BootVMResponse);
- rpc ConsoleVM (stream ConsoleVMRequest) returns (stream ConsoleVMResponse);
- rpc AttachNicVM (AttachNicVMRequest) returns (AttachNicVMResponse);
- rpc ShutdownVM (ShutdownVMRequest) returns (ShutdownVMResponse);
- rpc PingVM (PingVMRequest) returns (PingVMResponse);
+ rpc FetchImage (FetchImageRequest) returns (FetchImageResponse);
- rpc GetFeOSKernelLogs (GetFeOSKernelLogRequest) returns (stream GetFeOSKernelLogResponse);
- rpc GetFeOSLogs(GetFeOsLogRequest) returns (stream GetFeOsLogResponse);
+ rpc CreateVM (CreateVMRequest) returns (CreateVMResponse);
+ rpc GetVM (GetVMRequest) returns (GetVMResponse);
+ rpc BootVM (BootVMRequest) returns (BootVMResponse);
+ rpc ConsoleVM (stream ConsoleVMRequest) returns (stream ConsoleVMResponse);
+ rpc AttachNicVM (AttachNicVMRequest) returns (AttachNicVMResponse);
+ rpc ShutdownVM (ShutdownVMRequest) returns (ShutdownVMResponse);
+ rpc PingVM (PingVMRequest) returns (PingVMResponse);
+
+ rpc GetFeOSKernelLogs (GetFeOSKernelLogRequest) returns (stream GetFeOSKernelLogResponse);
+ rpc GetFeOSLogs(GetFeOsLogRequest) returns (stream GetFeOsLogResponse);
+}
+
+enum NicType {
+ MAC = 0;
+ PCI = 1;
+ TAP = 2;
}
message ConsoleVMRequest {
@@ -40,16 +46,20 @@ message GetFeOSKernelLogResponse {
message GetFeOsLogRequest {}
message GetFeOsLogResponse {
- string message = 1;
+ string message = 1;
}
message AttachNicVMRequest {
- string uuid = 1;
- string mac_address = 2;
- string pci_address = 3;
+ string uuid = 1;
+ NicType nic_type = 2;
+
+ oneof nic_data {
+ string mac_address = 3;
+ string pci_address = 4;
+ }
}
-message AttachNicVMResponse {}
+message AttachNicVMResponse {}
message RebootRequest {}
message RebootResponse {}
@@ -67,14 +77,13 @@ message HostInfoResponse {
}
message NetInterface {
- string name = 1;
- string pci_address = 2;
- string mac_address = 3;
+ string name = 1;
+ string pci_address = 2;
+ string mac_address = 3;
}
message Empty {}
-
message FetchImageRequest {
string image = 1;
}
@@ -83,12 +92,11 @@ message FetchImageResponse {
string uuid = 1;
}
-
message CreateVMRequest {
- uint32 cpu = 1;
- uint64 memory_bytes = 2;
+ uint32 cpu = 1;
+ uint64 memory_bytes = 2;
string image_uuid = 3;
- optional string ignition = 4;
+ optional string ignition = 4;
}
message CreateVMResponse {
@@ -96,14 +104,14 @@ message CreateVMResponse {
}
message GetVMRequest {
- string uuid = 1;
+ string uuid = 1;
}
message GetVMResponse {
string info = 1;
}
message BootVMRequest {
- string uuid = 1;
+ string uuid = 1;
}
message BootVMResponse {}
@@ -115,4 +123,4 @@ message ShutdownVMResponse {}
message PingVMRequest {
string uuid = 1;
}
-message PingVMResponse {}
\ No newline at end of file
+message PingVMResponse {}
diff --git a/src/bin/feos_cli/client.rs b/src/bin/feos_cli/client.rs
index cec4031..fbd60df 100644
--- a/src/bin/feos_cli/client.rs
+++ b/src/bin/feos_cli/client.rs
@@ -55,8 +55,10 @@ pub enum Command {
},
AttachNicVM {
uuid: String,
- mac_address: String,
- pci_address: String,
+ #[structopt(long)]
+ mac_address: Option,
+ #[structopt(long)]
+ pci_address: Option,
},
GetFeOSKernelLogs,
GetFeOSLogs,
@@ -152,7 +154,7 @@ pub async fn run_client(opt: Opt) -> Result<(), Box> {
Command::PingVM { uuid } => {
let request = Request::new(PingVmRequest { uuid });
let response = client.ping_vm(request).await?;
- println!("BOOT VM RESPONSE={:?}", response);
+ println!("PING VM RESPONSE={:?}", response);
}
Command::ShutdownVM { uuid } => {
let request = Request::new(ShutdownVmRequest { uuid });
@@ -164,11 +166,31 @@ pub async fn run_client(opt: Opt) -> Result<(), Box> {
mac_address,
pci_address,
} => {
+ let (nic_type, nic_data) = match (&mac_address, &pci_address) {
+ (Some(mac), None) => (
+ feos_grpc::NicType::Mac as i32,
+ Some(attach_nic_vm_request::NicData::MacAddress(mac.clone())),
+ ),
+ (None, Some(pci)) => (
+ feos_grpc::NicType::Pci as i32,
+ Some(attach_nic_vm_request::NicData::PciAddress(pci.clone())),
+ ),
+ (None, None) => (feos_grpc::NicType::Tap as i32, None),
+ (Some(_), Some(_)) => {
+ eprintln!("Error: Provide either --mac_address or --pci_address, not both.");
+ return Err(Box::new(std::io::Error::new(
+ std::io::ErrorKind::InvalidInput,
+ "Provide either --mac_address or --pci_address, not both.",
+ )));
+ }
+ };
+
let request = Request::new(AttachNicVmRequest {
uuid,
- mac_address,
- pci_address,
+ nic_type,
+ nic_data,
});
+
let response = client.attach_nic_vm(request).await?;
println!("ATTACH NIC VM RESPONSE={:?}", response);
}
diff --git a/src/daemon.rs b/src/daemon.rs
index 7e1fcfb..392e0d2 100644
--- a/src/daemon.rs
+++ b/src/daemon.rs
@@ -7,12 +7,12 @@ use tonic::{transport::Server, Request, Response, Status};
use crate::feos_grpc;
use crate::feos_grpc::feos_grpc_server::*;
use crate::feos_grpc::{
- AttachNicVmRequest, AttachNicVmResponse, BootVmRequest, BootVmResponse, ConsoleVmResponse,
- CreateVmRequest, CreateVmResponse, Empty, FetchImageRequest, FetchImageResponse,
- GetFeOsKernelLogRequest, GetFeOsKernelLogResponse, GetFeOsLogRequest, GetFeOsLogResponse,
- GetVmRequest, GetVmResponse, HostInfoRequest, HostInfoResponse, NetInterface, PingVmRequest,
- PingVmResponse, RebootRequest, RebootResponse, ShutdownRequest, ShutdownResponse,
- ShutdownVmRequest, ShutdownVmResponse,
+ attach_nic_vm_request::NicData, AttachNicVmRequest, AttachNicVmResponse, BootVmRequest,
+ BootVmResponse, ConsoleVmResponse, CreateVmRequest, CreateVmResponse, Empty, FetchImageRequest,
+ FetchImageResponse, GetFeOsKernelLogRequest, GetFeOsKernelLogResponse, GetFeOsLogRequest,
+ GetFeOsLogResponse, GetVmRequest, GetVmResponse, HostInfoRequest, HostInfoResponse,
+ NetInterface, NicType as ProtoNicType, PingVmRequest, PingVmResponse, RebootRequest,
+ RebootResponse, ShutdownRequest, ShutdownResponse, ShutdownVmRequest, ShutdownVmResponse,
};
use crate::host;
use crate::ringbuffer::*;
@@ -23,12 +23,13 @@ use hyper_util::rt::TokioIo;
use nix::libc::VMADDR_CID_ANY;
use nix::unistd::Uid;
use std::sync::Arc;
-use tokio::fs::File;
-use tokio::io::AsyncReadExt;
-use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
-use tokio::net::UnixStream;
-use tokio::sync::{mpsc, Mutex};
-use tokio::time::{sleep, Duration};
+use tokio::{
+ fs::File,
+ io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader},
+ net::UnixStream,
+ sync::{mpsc, Mutex},
+ time::{sleep, Duration},
+};
use tokio_stream::wrappers::ReceiverStream;
use tokio_vsock::{VsockAddr, VsockListener};
use tonic::transport::{Endpoint, Uri};
@@ -37,13 +38,14 @@ use uuid::Uuid;
use crate::filesystem::mount_virtual_filesystems;
use crate::isolated_container::{isolated_container_service, IsolatedContainerAPI};
-use crate::network::{configure_network_devices, configure_sriov};
+use crate::network::configure_network_devices;
#[derive(Debug)]
pub struct FeOSAPI {
vmm: Arc,
buffer: Arc,
log_receiver: Arc>>,
+ network: Arc,
}
impl FeOSAPI {
@@ -51,11 +53,13 @@ impl FeOSAPI {
vmm: Arc,
buffer: Arc,
log_receiver: Arc>>,
+ network: Arc,
) -> Self {
FeOSAPI {
vmm,
buffer,
log_receiver,
+ network,
}
}
@@ -80,6 +84,13 @@ impl FeOSAPI {
"failed to connect to cloud hypervisor",
)
}
+ vm::Error::NetworkingError(e) => {
+ info!("failed to prepare network {:?}", e);
+ Status::new(
+ tonic::Code::Internal,
+ format!("failed to prepare network: {:?}", e),
+ )
+ }
vm::Error::CHApiFailure(e) => {
info!("failed to connect to cloud hypervisor api: {:?}", e);
Status::new(
@@ -240,6 +251,13 @@ impl FeosGrpc for FeOSAPI {
.map_err(|_| Status::invalid_argument("Failed to parse UUID"))?;
self.vmm.boot_vm(id).map_err(|e| self.handle_error(e))?;
+ //TODO remove this sleep
+ sleep(Duration::from_secs(2)).await;
+ self.network
+ .start_dhcp(id)
+ .await
+ .map_err(vm::Error::NetworkingError)
+ .map_err(|e| self.handle_error(e))?;
Ok(Response::new(feos_grpc::BootVmResponse {}))
}
@@ -321,25 +339,46 @@ impl FeosGrpc for FeOSAPI {
&self,
request: Request,
) -> Result, Status> {
- info!("Got attach_nic_vm request");
+ info!("Received AttachNicVM request");
- let id = request.get_ref().uuid.to_owned();
- let id =
- Uuid::parse_str(&id).map_err(|_| Status::invalid_argument("failed to parse uuid"))?;
+ let req = request.into_inner();
- let net_config = if !request.get_ref().mac_address.is_empty() {
- vm::NetworkMode::MACAddress(request.get_ref().mac_address.clone())
- } else if !request.get_ref().pci_address.is_empty() {
- vm::NetworkMode::PCIAddress(request.get_ref().pci_address.clone())
- } else {
- return Err(Status::invalid_argument("no network config provided"));
+ let vm_uuid = Uuid::parse_str(&req.uuid)
+ .map_err(|_| Status::invalid_argument("Failed to parse UUID"))?;
+
+ let net_config = match ProtoNicType::try_from(req.nic_type) {
+ Ok(ProtoNicType::Mac) => {
+ if let Some(NicData::MacAddress(mac)) = req.nic_data {
+ vm::NetworkMode::MACAddress(mac)
+ } else {
+ return Err(Status::invalid_argument(
+ "mac_address must be provided for NIC type MAC",
+ ));
+ }
+ }
+ Ok(ProtoNicType::Pci) => {
+ if let Some(NicData::PciAddress(pci)) = req.nic_data {
+ vm::NetworkMode::PCIAddress(pci)
+ } else {
+ return Err(Status::invalid_argument(
+ "pci_address must be provided for NIC type PCI",
+ ));
+ }
+ }
+ Ok(ProtoNicType::Tap) => {
+ let tap_name = network::Manager::device_name(&vm_uuid);
+ vm::NetworkMode::TAPDeviceName(tap_name)
+ }
+ Err(_) => {
+ return Err(Status::invalid_argument("Invalid NIC type provided"));
+ }
};
self.vmm
- .add_net_device(id, net_config)
+ .add_net_device(vm_uuid, net_config)
.map_err(|e| self.handle_error(e))?;
- Ok(Response::new(feos_grpc::AttachNicVmResponse {}))
+ Ok(Response::new(AttachNicVmResponse {}))
}
async fn shutdown_vm(
@@ -351,6 +390,12 @@ impl FeosGrpc for FeOSAPI {
let id = Uuid::parse_str(&request.get_ref().uuid)
.map_err(|_| Status::invalid_argument("Failed to parse UUID"))?;
+ self.network
+ .stop_dhcp(id)
+ .await
+ .map_err(vm::Error::NetworkingError)
+ .map_err(|e| self.handle_error(e))?;
+
// TODO differentiate between kill and shutdown
self.vmm.kill_vm(id).map_err(|e| self.handle_error(e))?;
@@ -480,7 +525,7 @@ pub async fn daemon_start(
log_receiver: Arc>>,
is_nested: bool,
) -> Result<(), Box> {
- let api = FeOSAPI::new(vmm.clone(), buffer, log_receiver);
+ let api = FeOSAPI::new(vmm.clone(), buffer, log_receiver, network.clone());
let isolated_container_api = IsolatedContainerAPI::new(vmm, network);
if is_nested {
@@ -513,10 +558,9 @@ pub async fn daemon_start(
Ok(())
}
-pub async fn start_feos(ipv6_address: Ipv6Addr, prefix_length: u8) -> Result<(), String> {
+pub async fn start_feos(mut ipv6_address: Ipv6Addr, mut prefix_length: u8) -> Result<(), String> {
println!(
"
-
███████╗███████╗ ██████╗ ███████╗
██╔════╝██╔════╝██╔═══██╗██╔════╝
█████╗ █████╗ ██║ ██║███████╗
@@ -537,6 +581,10 @@ pub async fn start_feos(ipv6_address: Ipv6Addr, prefix_length: u8) -> Result<(),
warn!("Not running as root! (uid: {})", Uid::current());
}
+ if ipv6_address == Ipv6Addr::UNSPECIFIED {
+ info!("No --ipam flag found. Expecting Prefix Delegation from the dhcpv6 server");
+ }
+
if std::process::id() == 1 {
info!("Mounting virtual filesystems...");
mount_virtual_filesystems();
@@ -554,22 +602,25 @@ pub async fn start_feos(ipv6_address: Ipv6Addr, prefix_length: u8) -> Result<(),
if std::process::id() == 1 {
info!("Configuring network devices...");
- configure_network_devices()
+ if let Some((delegated_prefix, delegated_prefix_length)) = configure_network_devices()
.await
- .expect("could not configure network devices");
+ .expect("could not configure network devices")
+ {
+ ipv6_address = delegated_prefix;
+ prefix_length = delegated_prefix_length;
+ }
}
// Special stuff for pid 1
if std::process::id() == 1 && !is_nested {
- info!("Configuring sriov...");
- const VFS_NUM: u32 = 125;
+ info!("Skip configuring sriov...");
+ /*const VFS_NUM: u32 = 125;
if let Err(e) = configure_sriov(VFS_NUM).await {
warn!("failed to configure sriov: {}", e.to_string())
- }
+ }*/
}
let vmm = Manager::new(String::from("cloud-hypervisor"));
-
let network_manager = network::Manager::new(ipv6_address, prefix_length);
info!("Starting FeOS daemon...");
diff --git a/src/host/info.rs b/src/host/info.rs
index e9dc0fd..c67d988 100644
--- a/src/host/info.rs
+++ b/src/host/info.rs
@@ -33,7 +33,7 @@ fn get_pci_address(interface_name: &str) -> Option {
fn get_mac_address(interface_name: &str) -> Option {
let path = format!("/sys/class/net/{}/address", interface_name);
if let Ok(mac) = fs::read_to_string(path) {
- return Some(mac.trim().to_string());
+ Some(mac.trim().to_string())
} else {
None
}
diff --git a/src/isolated_container/mod.rs b/src/isolated_container/mod.rs
index 6451fb4..9d66f07 100644
--- a/src/isolated_container/mod.rs
+++ b/src/isolated_container/mod.rs
@@ -8,10 +8,12 @@ use hyper_util::rt::TokioIo;
use isolated_container_service::isolated_container_service_server::IsolatedContainerService;
use log::info;
use std::sync::Arc;
+use std::time::Duration;
use std::{collections::HashMap, sync::Mutex};
use std::{fmt::Debug, io, path::PathBuf};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::UnixStream;
+use tokio::time::sleep;
use tonic::transport::{Channel, Endpoint, Uri};
use tonic::{transport, Request, Response, Status};
use tower::service_fn;
@@ -117,7 +119,7 @@ impl IsolatedContainerAPI {
id,
2,
// TODO make configurable through container request
- 536870912,
+ 4294967296,
vm::BootMode::KernelBoot(vm::KernelBootMode {
kernel: PathBuf::from("/usr/share/feos/vmlinuz"),
initramfs: PathBuf::from("/usr/share/feos/initramfs"),
@@ -129,8 +131,6 @@ impl IsolatedContainerAPI {
)
.map_err(Error::VMError)?;
- self.vmm.boot_vm(id).map_err(Error::VMError)?;
-
self.vmm
.add_net_device(
id,
@@ -138,6 +138,8 @@ impl IsolatedContainerAPI {
)
.map_err(Error::VMError)?;
+ self.vmm.boot_vm(id).map_err(Error::VMError)?;
+
Ok(())
}
@@ -191,6 +193,8 @@ impl IsolatedContainerService for IsolatedContainerAPI {
let id = Uuid::new_v4();
self.prepare_vm(id).map_err(|e| self.handle_error(e))?;
+ //TODO get rid of sleep
+ sleep(Duration::from_secs(2)).await;
self.network
.start_dhcp(id)
@@ -209,9 +213,15 @@ impl IsolatedContainerService for IsolatedContainerAPI {
let response = client
.create_container(request)
.await
- .map_err(|_| match self.vmm.kill_vm(id) {
- Ok(_) => Error::Error("failed to create container".to_string()),
- Err(e) => Error::Error(format!("failed to create container: {:?}", e)),
+ .map_err(|e| {
+ info!("Failed to create container: {:?}", e);
+ match self.vmm.kill_vm(id) {
+ Ok(_) => Error::Error("failed to create container".to_string()),
+ Err(kill_error) => Error::Error(format!(
+ "failed to create container: {:?}, kill VM error: {:?}",
+ e, kill_error
+ )),
+ }
})
.map_err(|e| self.handle_error(e))?;
diff --git a/src/main.rs b/src/main.rs
index 42e7ca0..e96f6ef 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,11 +6,11 @@ use std::env;
use std::net::Ipv6Addr;
use std::str::FromStr;
use std::{env::args, ffi::CString};
-
use tokio::io;
use tokio::io::{AsyncBufReadExt, BufReader};
-#[tokio::main]
+//TODO remove this in future, the reason https://github.com/youki-dev/youki/issues/2144
+#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), String> {
let mut ipv6_address = Ipv6Addr::UNSPECIFIED;
let mut prefix_length = 64;
@@ -36,14 +36,18 @@ async fn main() -> Result<(), String> {
fn parse_command_line() -> Result<(Ipv6Addr, u8), String> {
let args: Vec = env::args().collect();
- if args.len() != 3 {
- return Err("Usage: --ipam /".into());
+ if args.len() < 2 {
+ return Ok((Ipv6Addr::UNSPECIFIED, 64));
}
if args[1] != "--ipam" {
return Err("Expected '--ipam' flag".into());
}
+ if args.len() != 3 {
+ return Err("Usage: --ipam /".into());
+ }
+
let prefix_input = &args[2];
let parts: Vec<&str> = prefix_input.split('/').collect();
diff --git a/src/move_root.rs b/src/move_root.rs
index 3de343b..269457f 100644
--- a/src/move_root.rs
+++ b/src/move_root.rs
@@ -1,3 +1,4 @@
+use crate::fsmount::{fsconfig, fsmount, fsopen, FSCONFIG_CMD_CREATE, FSCONFIG_SET_STRING};
use nix::{
fcntl::{openat, OFlag},
mount::{mount, MsFlags},
@@ -14,8 +15,6 @@ use std::{
path::Path,
};
-use crate::fsmount::{fsconfig, fsmount, fsopen, FSCONFIG_CMD_CREATE, FSCONFIG_SET_STRING};
-
#[allow(unsafe_code)]
pub fn get_root_fstype() -> Result> {
let proc_fs_raw = fsopen("proc", 0)?;
diff --git a/src/network/dhcpv6.rs b/src/network/dhcpv6.rs
index 55671a2..488a24b 100644
--- a/src/network/dhcpv6.rs
+++ b/src/network/dhcpv6.rs
@@ -252,15 +252,26 @@ pub fn is_dhcpv6_needed(interface_name: String, ignore_ra_flag: bool) -> Option<
sender_ipv6_address
}
+pub struct PrefixInfo {
+ pub prefix: Ipv6Addr,
+ pub prefix_length: u8,
+}
+
+pub struct Dhcpv6Result {
+ pub address: Ipv6Addr,
+ pub prefix: Option,
+}
+
pub async fn run_dhcpv6_client(
interface_name: String,
-) -> Result> {
+) -> Result> {
let chaddr = vec![
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
];
let random_xid: [u8; 3] = [0x12, 0x34, 0x56];
let multicast_address = "[FF02::1:2]:547".parse::().unwrap();
let mut ia_addr_confirm: Option = None;
+ let mut ia_pd_confirm: Option = None;
let interface_index = get_interface_index(interface_name.clone()).await?;
let socket = create_multicast_socket(interface_name.clone(), interface_index, 546)?;
@@ -278,6 +289,8 @@ pub async fn run_dhcpv6_client(
oro.opts.push(OptionCode::ClientFqdn);
oro.opts.push(OptionCode::SntpServers);
oro.opts.push(OptionCode::RapidCommit);
+ oro.opts.push(OptionCode::IAPD);
+ oro.opts.push(OptionCode::IAPrefix);
msg.opts_mut().insert(DhcpOption::ORO(oro));
@@ -300,6 +313,27 @@ pub async fn run_dhcpv6_client(
msg.opts_mut().insert(DhcpOption::IANA(iana_instance));
+ // Request Prefix Delegation
+ let iaprefix_instance = IAPrefix {
+ preferred_lifetime: 0,
+ prefix_len: 80,
+ opts: DhcpOptions::default(),
+ valid_lifetime: 0,
+ prefix_ip: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0),
+ };
+
+ let mut iapd_opts = DhcpOptions::default();
+ iapd_opts.insert(DhcpOption::IAPrefix(iaprefix_instance));
+
+ let iapd_instance = IAPD {
+ id: 456,
+ t1: 3600,
+ t2: 7200,
+ opts: iapd_opts,
+ };
+
+ msg.opts_mut().insert(DhcpOption::IAPD(iapd_instance));
+
let mut buf = Vec::new();
let mut encoder = Encoder::new(&mut buf);
msg.encode(&mut encoder)?;
@@ -311,6 +345,7 @@ pub async fn run_dhcpv6_client(
let response = Message::decode(&mut dhcproto::v6::Decoder::new(&recv_buf[..size]))?;
let mut serverid: Option<&DhcpOption> = None;
let mut ia_addr: Option<&DhcpOption> = None;
+ let mut ia_pd: Option<&DhcpOption> = None;
match response.msg_type() {
MessageType::Advertise => {
@@ -320,6 +355,11 @@ pub async fn run_dhcpv6_client(
ia_addr = Some(ia_addr_opt);
}
}
+ if let Some(DhcpOption::IAPD(iapd)) = response.opts().get(OptionCode::IAPD) {
+ if let Some(iaprefix_opt) = iapd.opts.get(OptionCode::IAPrefix) {
+ ia_pd = Some(iaprefix_opt);
+ }
+ }
if let Some(server_option) = response.opts().get(OptionCode::ServerId) {
serverid = Some(server_option);
}
@@ -361,6 +401,22 @@ pub async fn run_dhcpv6_client(
warn!("No IP was found in Advertise message");
}
+ if let Some(DhcpOption::IAPrefix(iaprefix)) = ia_pd {
+ let iapd_instance = IAPD {
+ id: 456,
+ t1: 3600,
+ t2: 7200,
+ opts: {
+ let mut opts = DhcpOptions::default();
+ opts.insert(DhcpOption::IAPrefix((*iaprefix).clone()));
+ opts
+ },
+ };
+ request_msg
+ .opts_mut()
+ .insert(DhcpOption::IAPD(iapd_instance));
+ }
+
buf.clear();
request_msg.encode(&mut Encoder::new(&mut buf))?;
socket.send_to(&buf, multicast_address).await?;
@@ -371,6 +427,13 @@ pub async fn run_dhcpv6_client(
ia_addr_confirm = Some((*ia_addr_opt).clone());
}
}
+ if let Some(DhcpOption::IAPD(iapd)) = response.opts().get(OptionCode::IAPD) {
+ if let Some(DhcpOption::IAPrefix(iaprefix)) =
+ iapd.opts.get(OptionCode::IAPrefix)
+ {
+ ia_pd_confirm = Some((*iaprefix).clone());
+ }
+ }
let mut confirm_msg = Message::new(MessageType::Confirm);
confirm_msg.set_xid(random_xid);
@@ -396,7 +459,25 @@ pub async fn run_dhcpv6_client(
"DHCPv6 processing finished, setting IPv6 address {}",
ia_a.addr
);
- return Ok(ia_a.addr);
+
+ let prefix_info = ia_pd_confirm.map(|iaprefix| PrefixInfo {
+ prefix: iaprefix.prefix_ip,
+ prefix_length: iaprefix.prefix_len,
+ });
+
+ if let Some(ref pfx) = prefix_info {
+ info!(
+ "Received delegated prefix {} with length {}",
+ pfx.prefix, pfx.prefix_length
+ );
+ } else {
+ info!("No prefix delegation received.");
+ }
+
+ return Ok(Dhcpv6Result {
+ address: ia_a.addr,
+ prefix: prefix_info,
+ });
}
Err("No valid address received".into())
@@ -926,7 +1007,7 @@ pub fn add_to_ipv6(addr: Ipv6Addr, prefix_length: u8, increment: u128) -> Ipv6Ad
Ipv6Addr::from(new_addr)
}
-async fn _set_ipv6_gateway(
+pub async fn set_ipv6_gateway(
handle: &Handle,
interface_name: &str,
ipv6_gateway: Ipv6Addr,
diff --git a/src/network/mod.rs b/src/network/mod.rs
index e75238b..642ba74 100644
--- a/src/network/mod.rs
+++ b/src/network/mod.rs
@@ -16,8 +16,8 @@ use crate::network::dhcpv6::{
add_ipv6_route, add_to_ipv6, adjust_base_ip, run_dhcpv6_server, IpRange,
};
use radv::start_radv_server;
+pub use utils::_configure_sriov;
pub use utils::configure_network_devices;
-pub use utils::configure_sriov;
#[derive(Debug)]
pub enum Error {
diff --git a/src/network/utils.rs b/src/network/utils.rs
index 42d319b..ceb8e81 100644
--- a/src/network/utils.rs
+++ b/src/network/utils.rs
@@ -1,9 +1,12 @@
+use std::fs::File;
use std::io;
+use std::io::Write;
use crate::network::dhcpv6::*;
use futures::stream::TryStreamExt;
-use log::{info, warn};
-use rtnetlink::new_connection;
+use log::{debug, info, warn};
+use rtnetlink::{new_connection, Handle, IpVersion};
+use std::net::Ipv6Addr;
use tokio::fs::{read_link, OpenOptions};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::time::{self, sleep, Duration};
@@ -19,16 +22,20 @@ use pnet::packet::udp::UdpPacket;
use pnet::packet::Packet;
use netlink_packet_route::neighbour::*;
+use netlink_packet_route::route::{RouteAddress, RouteAttribute};
const INTERFACE_NAME: &str = "eth0";
-pub async fn configure_network_devices() -> Result<(), String> {
+pub async fn configure_network_devices() -> Result