From 13950e985e6eff9cd7eadd5dcbfe1c39c1dce080 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Fri, 15 Nov 2024 14:48:49 +0100 Subject: [PATCH 1/7] Introduce IPv6 prefix delegation support Signed-off-by: Guvenc Gulce --- Makefile | 4 +- proto/feos.proto | 70 +++++++++++++----------- src/bin/feos_cli/client.rs | 32 +++++++++-- src/daemon.rs | 107 ++++++++++++++++++++++++++++--------- src/main.rs | 9 ++-- src/network/dhcpv6.rs | 85 ++++++++++++++++++++++++++++- src/network/utils.rs | 21 ++++++-- src/vm/mod.rs | 1 + 8 files changed, 257 insertions(+), 72 deletions(-) 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/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..7a888b2 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -7,16 +7,16 @@ 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::*; -use crate::vm::{self}; +use crate::vm::{self, NetworkMode}; use crate::vm::{image, Manager}; use crate::{container, network}; use hyper_util::rt::TokioIo; @@ -44,6 +44,7 @@ pub struct FeOSAPI { vmm: Arc, buffer: Arc, log_receiver: Arc>>, + network: Arc, } impl FeOSAPI { @@ -51,11 +52,13 @@ impl FeOSAPI { vmm: Arc, buffer: Arc, log_receiver: Arc>>, + network: Arc, ) -> Self { FeOSAPI { vmm, buffer, log_receiver, + network, } } @@ -80,6 +83,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( @@ -239,7 +249,19 @@ impl FeosGrpc for FeOSAPI { let id = Uuid::parse_str(&request.get_ref().uuid) .map_err(|_| Status::invalid_argument("Failed to parse UUID"))?; + self.vmm + .add_net_device( + id, + NetworkMode::TAPDeviceName(network::Manager::vm_tap_name(&id)), + ) + .map_err(|e| self.handle_error(e))?; self.vmm.boot_vm(id).map_err(|e| self.handle_error(e))?; + 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 +343,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 vm_uuid = Uuid::parse_str(&req.uuid) + .map_err(|_| Status::invalid_argument("Failed to parse UUID"))?; - 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 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 +394,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 +529,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 +562,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 +585,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,9 +606,13 @@ 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 @@ -569,7 +625,6 @@ pub async fn start_feos(ipv6_address: Ipv6Addr, prefix_length: u8) -> Result<(), } 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/main.rs b/src/main.rs index 42e7ca0..8ed76b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ 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}; @@ -36,14 +35,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/network/dhcpv6.rs b/src/network/dhcpv6.rs index 55671a2..631b0b2 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()) diff --git a/src/network/utils.rs b/src/network/utils.rs index 42d319b..ab60971 100644 --- a/src/network/utils.rs +++ b/src/network/utils.rs @@ -4,6 +4,7 @@ use crate::network::dhcpv6::*; use futures::stream::TryStreamExt; use log::{info, warn}; use rtnetlink::new_connection; +use std::net::Ipv6Addr; use tokio::fs::{read_link, OpenOptions}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::time::{self, sleep, Duration}; @@ -22,11 +23,12 @@ use netlink_packet_route::neighbour::*; const INTERFACE_NAME: &str = "eth0"; -pub async fn configure_network_devices() -> Result<(), String> { +pub async fn configure_network_devices() -> Result, String> { let ignore_ra_flag = true; // Till the RA has the correct flags (O or M), ignore the flag let interface_name = String::from(INTERFACE_NAME); let (connection, handle, _) = new_connection().unwrap(); let mut mac_bytes_option: Option> = None; + let mut delegated_prefix_option: Option<(Ipv6Addr, u8)> = None; tokio::spawn(connection); let mut link_ts = handle @@ -107,7 +109,20 @@ pub async fn configure_network_devices() -> Result<(), String> { if let Some(ipv6_gateway) = is_dhcpv6_needed(interface_name.clone(), ignore_ra_flag) { time::sleep(Duration::from_secs(4)).await; match run_dhcpv6_client(interface_name.clone()).await { - Ok(addr) => send_neigh_solicitation(interface_name.clone(), &ipv6_gateway, &addr), + Ok(result) => { + send_neigh_solicitation(interface_name.clone(), &ipv6_gateway, &result.address); + if let Some(prefix_info) = result.prefix { + let delegated_prefix = prefix_info.prefix; + let prefix_length = prefix_info.prefix_length; + info!( + "Received delegated prefix {} with length {}", + delegated_prefix, prefix_length + ); + delegated_prefix_option = Some((delegated_prefix, prefix_length)); + } else { + info!("No prefix delegation received."); + } + } Err(e) => warn!("Error: {}", e), } } @@ -130,7 +145,7 @@ pub async fn configure_network_devices() -> Result<(), String> { } } - Ok(()) + Ok(delegated_prefix_option) } fn format_mac(bytes: Vec) -> String { diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 41ef1ac..b399cec 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -32,6 +32,7 @@ pub enum Error { InvalidInput(TryFromIntError), CHCommandFailure(std::io::Error), CHApiFailure(api_client::Error), + NetworkingError(network::Error), } pub enum BootMode { From 7162715932815486713eff6185680e3f3db4f605 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Mon, 18 Nov 2024 17:28:27 +0100 Subject: [PATCH 2/7] Trigger OCI image build Signed-off-by: Guvenc Gulce --- .github/workflows/release-oci.yaml | 1 + src/daemon.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-oci.yaml b/.github/workflows/release-oci.yaml index 24dbdfa..f76d5b7 100644 --- a/.github/workflows/release-oci.yaml +++ b/.github/workflows/release-oci.yaml @@ -5,6 +5,7 @@ on: branches: - master - feat/container + - feature/prefix_delegation tags: - '*' paths-ignore: diff --git a/src/daemon.rs b/src/daemon.rs index 7a888b2..699303a 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -381,7 +381,7 @@ impl FeosGrpc for FeOSAPI { self.vmm .add_net_device(vm_uuid, net_config) .map_err(|e| self.handle_error(e))?; - + Ok(Response::new(AttachNicVmResponse {})) } From 5276bf5a11be723150494bfdccaba0e5119283c6 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 19 Nov 2024 19:42:12 +0100 Subject: [PATCH 3/7] Isolated Container expects FeOS kernel and initramfs in the rootfs To be able to boot a nested FeOS, make vmlinuz and initramfs files part of the rootfs. Signed-off-by: Guvenc Gulce --- hack/initramfs/make.mk | 2 ++ hack/initramfs/mk-initramfs | 4 ++++ 2 files changed, 6 insertions(+) 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" From 7b5b30e7a146c22cbd374d5011320bea43257e71 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Mon, 25 Nov 2024 17:53:42 +0100 Subject: [PATCH 4/7] Disable SR-IOV configuration Signed-off-by: Guvenc Gulce --- src/daemon.rs | 8 ++++---- src/network/mod.rs | 2 +- src/network/utils.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/daemon.rs b/src/daemon.rs index 699303a..dfeec8e 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -37,7 +37,7 @@ 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 { @@ -617,11 +617,11 @@ pub async fn start_feos(mut ipv6_address: Ipv6Addr, mut prefix_length: u8) -> Re // 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")); 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 ab60971..ed6635f 100644 --- a/src/network/utils.rs +++ b/src/network/utils.rs @@ -156,7 +156,7 @@ fn format_mac(bytes: Vec) -> String { .join(":") } -pub async fn configure_sriov(num_vfs: u32) -> Result<(), String> { +pub async fn _configure_sriov(num_vfs: u32) -> Result<(), String> { let base_path = format!("/sys/class/net/{}/device", INTERFACE_NAME); let file_path = format!("{}/sriov_numvfs", base_path); From 34fa397bfd641ac8bc2224853d6e13a9daca470f Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Tue, 26 Nov 2024 13:16:36 +0100 Subject: [PATCH 5/7] Prepare to run on metal Signed-off-by: Guvenc Gulce --- .github/workflows/release-oci.yaml | 4 +- Cargo.lock | 2 +- hack/kernel/config/feos-linux-6.6.60.config | 10 +- hack/libvirt/libvirt-kvm.xml | 4 +- src/daemon.rs | 21 ++-- src/filesystem.rs | 15 +++ src/host/info.rs | 2 +- src/isolated_container/mod.rs | 9 +- src/main.rs | 2 +- src/move_root.rs | 3 +- src/network/dhcpv6.rs | 2 +- src/network/utils.rs | 123 +++++++++++++++++++- 12 files changed, 164 insertions(+), 33 deletions(-) diff --git a/.github/workflows/release-oci.yaml b/.github/workflows/release-oci.yaml index f76d5b7..0c81269 100644 --- a/.github/workflows/release-oci.yaml +++ b/.github/workflows/release-oci.yaml @@ -75,8 +75,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/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/src/daemon.rs b/src/daemon.rs index dfeec8e..4ce857e 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -16,19 +16,20 @@ use crate::feos_grpc::{ }; use crate::host; use crate::ringbuffer::*; -use crate::vm::{self, NetworkMode}; +use crate::vm::{self}; use crate::vm::{image, Manager}; use crate::{container, network}; 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}; @@ -249,12 +250,6 @@ impl FeosGrpc for FeOSAPI { let id = Uuid::parse_str(&request.get_ref().uuid) .map_err(|_| Status::invalid_argument("Failed to parse UUID"))?; - self.vmm - .add_net_device( - id, - NetworkMode::TAPDeviceName(network::Manager::vm_tap_name(&id)), - ) - .map_err(|e| self.handle_error(e))?; self.vmm.boot_vm(id).map_err(|e| self.handle_error(e))?; sleep(Duration::from_secs(2)).await; self.network diff --git a/src/filesystem.rs b/src/filesystem.rs index 335a56d..992692b 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,5 +1,7 @@ use log::debug; use nix::mount::{mount, MsFlags}; +use std::fs::File; +use std::io::{Error, Write}; pub fn mount_virtual_filesystems() { const NONE: Option<&'static [u8]> = None; @@ -53,4 +55,17 @@ pub fn mount_virtual_filesystems() { NONE, ) .unwrap_or_else(|e| panic!("/sys/fs/cgroup mount failed: {e}")); + + enable_ipv6_forwarding().unwrap_or_else(|e| panic!("Failed to enable ipv6 forwarding: {e}")); +} + +fn enable_ipv6_forwarding() -> Result<(), Error> { + let forwarding_paths = ["/proc/sys/net/ipv6/conf/all/forwarding"]; + + for path in forwarding_paths { + let mut file = File::create(path)?; + file.write_all(b"1")?; + } + + Ok(()) } 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..fc2ede7 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,7 @@ impl IsolatedContainerService for IsolatedContainerAPI { let id = Uuid::new_v4(); self.prepare_vm(id).map_err(|e| self.handle_error(e))?; + sleep(Duration::from_secs(2)).await; self.network .start_dhcp(id) diff --git a/src/main.rs b/src/main.rs index 8ed76b5..1107f8a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use std::{env::args, ffi::CString}; use tokio::io; use tokio::io::{AsyncBufReadExt, BufReader}; -#[tokio::main] +#[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), String> { let mut ipv6_address = Ipv6Addr::UNSPECIFIED; let mut prefix_length = 64; 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 631b0b2..488a24b 100644 --- a/src/network/dhcpv6.rs +++ b/src/network/dhcpv6.rs @@ -1007,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/utils.rs b/src/network/utils.rs index ed6635f..26354ba 100644 --- a/src/network/utils.rs +++ b/src/network/utils.rs @@ -1,9 +1,10 @@ +use std::error::Error; use std::io; 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}; @@ -20,6 +21,7 @@ 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"; @@ -122,6 +124,13 @@ pub async fn configure_network_devices() -> Result, Strin } else { info!("No prefix delegation received."); } + info!( + "Setting IPv6 gateway to {} on interface {}", + ipv6_gateway, interface_name + ); + if let Err(e) = set_ipv6_gateway(&handle, &interface_name, ipv6_gateway).await { + warn!("Failed to set IPv6 gateway: {}", e); + } } Err(e) => warn!("Error: {}", e), } @@ -148,6 +157,116 @@ pub async fn configure_network_devices() -> Result, Strin Ok(delegated_prefix_option) } +// Keep for debugging purposes +async fn _print_ipv6_routes( + handle: &Handle, + iface_index: u32, + interface_name: &str, +) -> Result<(), Box> { + info!("IPv6 Routes:"); + + let mut route_ts = handle.route().get(IpVersion::V6).execute(); + + while let Some(route_msg) = route_ts + .try_next() + .await + .map_err(|e| format!("Could not get route: {}", e))? + { + let mut destination: Option = None; + let mut gateway: Option = None; + let mut oif: Option = None; + + for attr in &route_msg.attributes { + match attr { + RouteAttribute::Oif(oif_idx) => { + oif = Some(*oif_idx); + debug!("Route OIF: {}", oif_idx); + } + + RouteAttribute::Destination(dest) => { + match dest { + RouteAddress::Inet6(addr) => { + destination = Some(format!( + "{}/{}", + addr, route_msg.header.destination_prefix_length + )); + debug!("Parsed IPv6 Destination: {}", addr); + } + RouteAddress::Other(v) => { + if v.is_empty() { + destination = Some("::/0".to_string()); + debug!("Parsed Default Route"); + } else { + // Unknown or unsupported address + let hex_str = v + .iter() + .map(|b| format!("{:02x}", b)) + .collect::>() + .join(":"); + destination = Some(format!("unknown({})", hex_str)); + debug!("Parsed Unknown Destination: {}", hex_str); + } + } + _ => { + debug!("Unhandled Destination variant"); + } + } + } + + RouteAttribute::Gateway(gw) => { + match gw { + RouteAddress::Inet6(addr) => { + gateway = Some(addr.to_string()); + debug!("Parsed IPv6 Gateway: {}", addr); + } + RouteAddress::Other(v) => { + // Some other form of gateway, handle if needed + if v.is_empty() { + debug!("Parsed Empty Gateway"); + } else { + let hex_str = v + .iter() + .map(|b| format!("{:02x}", b)) + .collect::>() + .join(":"); + gateway = Some(format!("unknown({})", hex_str)); + debug!("Parsed Unknown Gateway: {}", hex_str); + } + } + _ => { + debug!("Unhandled Gateway variant"); + } + } + } + _ => {} + } + } + + if oif != Some(iface_index) { + debug!( + "Skipping route not associated with interface '{}'", + interface_name + ); + continue; + } + + if route_msg.header.destination_prefix_length == 0 && destination.is_none() { + destination = Some("::/0".to_string()); + debug!("Default route detected (no destination attribute)"); + } + + let dest_str = destination.unwrap_or_else(|| "unknown".to_string()); + let mut route_str = dest_str.to_string(); + if let Some(gw) = gateway { + route_str.push_str(&format!(" via {}", gw)); + } + route_str.push_str(&format!(" dev {}", interface_name)); + + info!("- {}", route_str); + } + Ok(()) +} + fn format_mac(bytes: Vec) -> String { bytes .iter() From ec6506d3cd4c44d41635ce46ab477bf27c2993de Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Wed, 11 Dec 2024 15:43:59 +0100 Subject: [PATCH 6/7] Debug commit Signed-off-by: Guvenc Gulce --- src/isolated_container/mod.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/isolated_container/mod.rs b/src/isolated_container/mod.rs index fc2ede7..6689b75 100644 --- a/src/isolated_container/mod.rs +++ b/src/isolated_container/mod.rs @@ -212,9 +212,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))?; From b7288289e79c34cecaa4369028c2b91c77d6b205 Mon Sep 17 00:00:00 2001 From: Guvenc Gulce Date: Mon, 16 Dec 2024 13:04:02 +0100 Subject: [PATCH 7/7] Incorporate review comments Signed-off-by: Guvenc Gulce --- .github/workflows/release-oci.yaml | 2 -- src/daemon.rs | 1 + src/filesystem.rs | 15 --------------- src/isolated_container/mod.rs | 1 + src/main.rs | 1 + src/network/utils.rs | 18 ++++++++++++++++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release-oci.yaml b/.github/workflows/release-oci.yaml index 0c81269..7966514 100644 --- a/.github/workflows/release-oci.yaml +++ b/.github/workflows/release-oci.yaml @@ -4,8 +4,6 @@ on: push: branches: - master - - feat/container - - feature/prefix_delegation tags: - '*' paths-ignore: diff --git a/src/daemon.rs b/src/daemon.rs index 4ce857e..392e0d2 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -251,6 +251,7 @@ 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) diff --git a/src/filesystem.rs b/src/filesystem.rs index 992692b..335a56d 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,7 +1,5 @@ use log::debug; use nix::mount::{mount, MsFlags}; -use std::fs::File; -use std::io::{Error, Write}; pub fn mount_virtual_filesystems() { const NONE: Option<&'static [u8]> = None; @@ -55,17 +53,4 @@ pub fn mount_virtual_filesystems() { NONE, ) .unwrap_or_else(|e| panic!("/sys/fs/cgroup mount failed: {e}")); - - enable_ipv6_forwarding().unwrap_or_else(|e| panic!("Failed to enable ipv6 forwarding: {e}")); -} - -fn enable_ipv6_forwarding() -> Result<(), Error> { - let forwarding_paths = ["/proc/sys/net/ipv6/conf/all/forwarding"]; - - for path in forwarding_paths { - let mut file = File::create(path)?; - file.write_all(b"1")?; - } - - Ok(()) } diff --git a/src/isolated_container/mod.rs b/src/isolated_container/mod.rs index 6689b75..9d66f07 100644 --- a/src/isolated_container/mod.rs +++ b/src/isolated_container/mod.rs @@ -193,6 +193,7 @@ 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 diff --git a/src/main.rs b/src/main.rs index 1107f8a..e96f6ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use std::{env::args, ffi::CString}; use tokio::io; use tokio::io::{AsyncBufReadExt, BufReader}; +//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; diff --git a/src/network/utils.rs b/src/network/utils.rs index 26354ba..ceb8e81 100644 --- a/src/network/utils.rs +++ b/src/network/utils.rs @@ -1,5 +1,6 @@ -use std::error::Error; +use std::fs::File; use std::io; +use std::io::Write; use crate::network::dhcpv6::*; use futures::stream::TryStreamExt; @@ -33,6 +34,8 @@ pub async fn configure_network_devices() -> Result, Strin let mut delegated_prefix_option: Option<(Ipv6Addr, u8)> = None; tokio::spawn(connection); + enable_ipv6_forwarding().map_err(|e| format!("Failed to enable ipv6 forwarding: {}", e))?; + let mut link_ts = handle .link() .get() @@ -157,12 +160,23 @@ pub async fn configure_network_devices() -> Result, Strin Ok(delegated_prefix_option) } +pub fn enable_ipv6_forwarding() -> Result<(), std::io::Error> { + let forwarding_paths = ["/proc/sys/net/ipv6/conf/all/forwarding"]; + + for path in forwarding_paths { + let mut file = File::create(path)?; + file.write_all(b"1")?; + } + + Ok(()) +} + // Keep for debugging purposes async fn _print_ipv6_routes( handle: &Handle, iface_index: u32, interface_name: &str, -) -> Result<(), Box> { +) -> Result<(), Box> { info!("IPv6 Routes:"); let mut route_ts = handle.route().get(IpVersion::V6).execute();