krata: event-based network backend startup and api enhancements

This commit is contained in:
Alex Zenla 2024-03-27 02:54:39 +00:00
parent 63c0feb053
commit 66465793cd
No known key found for this signature in database
GPG Key ID: 067B238899B51269
29 changed files with 346 additions and 229 deletions

View File

@ -7,11 +7,15 @@ resolver = "2"
[dependencies]
anyhow = { workspace = true }
libc = { workspace = true }
log = { workspace = true }
once_cell = { workspace = true }
prost = { workspace = true }
prost-reflect = { workspace = true }
serde = { workspace = true }
tonic = { workspace = true }
tokio = { workspace = true }
tokio-stream = { workspace = true }
tower = { workspace = true }
url = { workspace = true }
[build-dependencies]

View File

@ -1,7 +1,7 @@
use crate::{dial::ControlDialAddress, v1::control::control_service_client::ControlServiceClient};
#[cfg(not(unix))]
use anyhow::anyhow;
use anyhow::Result;
use krata::{dial::ControlDialAddress, v1::control::control_service_client::ControlServiceClient};
#[cfg(unix)]
use tokio::net::UnixStream;
#[cfg(unix)]

View File

@ -1,7 +1,7 @@
use std::sync::Arc;
use crate::v1::control::{watch_events_reply::Event, WatchEventsReply};
use anyhow::Result;
use krata::v1::control::{watch_events_reply::Event, WatchEventsReply};
use log::trace;
use tokio::{sync::broadcast, task::JoinHandle};
use tokio_stream::StreamExt;

View File

@ -1,10 +1,13 @@
use once_cell::sync::Lazy;
use prost_reflect::DescriptorPool;
pub mod dial;
pub mod launchcfg;
pub mod v1;
pub mod client;
pub mod dial;
pub mod events;
pub mod launchcfg;
#[cfg(target_os = "linux")]
pub mod ethtool;

View File

@ -1,11 +1,11 @@
use anyhow::Result;
use clap::Parser;
use krata::v1::control::control_service_client::ControlServiceClient;
use krata::{events::EventStream, v1::control::control_service_client::ControlServiceClient};
use tokio::select;
use tonic::transport::Channel;
use crate::{console::StdioConsoleStream, events::EventStream};
use crate::console::StdioConsoleStream;
use super::resolve_guest;

View File

@ -1,17 +1,20 @@
use anyhow::Result;
use clap::Parser;
use krata::v1::{
use krata::{
events::EventStream,
v1::{
common::GuestStatus,
control::{
control_service_client::ControlServiceClient, watch_events_reply::Event,
DestroyGuestRequest,
},
},
};
use log::error;
use tonic::{transport::Channel, Request};
use crate::{cli::resolve_guest, events::EventStream};
use crate::cli::resolve_guest;
#[derive(Parser)]
pub struct DestroyCommand {

View File

@ -2,20 +2,24 @@ use std::collections::HashMap;
use anyhow::Result;
use clap::Parser;
use krata::v1::{
use krata::{
events::EventStream,
v1::{
common::{
guest_image_spec::Image, GuestEnvVar, GuestImageSpec, GuestOciImageSpec, GuestSpec,
GuestStatus,
guest_image_spec::Image, GuestImageSpec, GuestOciImageSpec, GuestSpec, GuestStatus,
GuestTaskSpec, GuestTaskSpecEnvVar,
},
control::{
control_service_client::ControlServiceClient, watch_events_reply::Event, CreateGuestRequest,
control_service_client::ControlServiceClient, watch_events_reply::Event,
CreateGuestRequest,
},
},
};
use log::error;
use tokio::select;
use tonic::{transport::Channel, Request};
use crate::{console::StdioConsoleStream, events::EventStream};
use crate::console::StdioConsoleStream;
#[derive(Parser)]
pub struct LauchCommand {
@ -51,14 +55,17 @@ impl LauchCommand {
}),
vcpus: self.cpus,
mem: self.mem,
env: env_map(&self.env.unwrap_or_default())
task: Some(GuestTaskSpec {
environment: env_map(&self.env.unwrap_or_default())
.iter()
.map(|(key, value)| GuestEnvVar {
.map(|(key, value)| GuestTaskSpecEnvVar {
key: key.clone(),
value: value.clone(),
})
.collect(),
run: self.run,
command: self.run,
}),
annotations: vec![],
}),
};
let response = client

View File

@ -1,20 +1,20 @@
use anyhow::{anyhow, Result};
use clap::{Parser, ValueEnum};
use cli_tables::Table;
use krata::v1::{
use krata::{
events::EventStream,
v1::{
common::{guest_image_spec::Image, Guest},
control::{
control_service_client::ControlServiceClient, ListGuestsRequest, ResolveGuestRequest,
},
},
};
use serde_json::Value;
use tonic::{transport::Channel, Request};
use crate::{
events::EventStream,
format::{guest_state_text, kv2line, proto2dynamic, proto2kv},
};
use crate::format::{guest_state_text, kv2line, proto2dynamic, proto2kv};
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum ListFormat {
@ -106,13 +106,13 @@ impl ListCommand {
.state
.as_ref()
.and_then(|x| x.network.as_ref())
.map(|x| x.ipv4.as_str())
.map(|x| x.guest_ipv4.as_str())
.unwrap_or("unknown");
let ipv6 = guest
.state
.as_ref()
.and_then(|x| x.network.as_ref())
.map(|x| x.ipv6.as_str())
.map(|x| x.guest_ipv6.as_str())
.unwrap_or("unknown");
let Some(spec) = guest.spec else {
continue;

View File

@ -7,13 +7,15 @@ pub mod watch;
use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand};
use krata::v1::control::{
use krata::{
client::ControlClientProvider,
events::EventStream,
v1::control::{
control_service_client::ControlServiceClient, ResolveGuestRequest, WatchEventsRequest,
},
};
use tonic::{transport::Channel, Request};
use crate::{client::ControlClientProvider, events::EventStream};
use self::{
attach::AttachCommand, destroy::DestroyCommand, launch::LauchCommand, list::ListCommand,
resolve::ResolveCommand, watch::WatchCommand,

View File

@ -1,13 +1,13 @@
use anyhow::Result;
use clap::{Parser, ValueEnum};
use krata::v1::{common::Guest, control::watch_events_reply::Event};
use krata::{
events::EventStream,
v1::{common::Guest, control::watch_events_reply::Event},
};
use prost_reflect::ReflectMessage;
use serde_json::Value;
use crate::{
events::EventStream,
format::{guest_state_text, kv2line, proto2dynamic, proto2kv},
};
use crate::format::{guest_state_text, kv2line, proto2dynamic, proto2kv};
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum WatchFormat {

View File

@ -4,9 +4,12 @@ use crossterm::{
terminal::{disable_raw_mode, enable_raw_mode, is_raw_mode_enabled},
tty::IsTty,
};
use krata::v1::{
use krata::{
events::EventStream,
v1::{
common::GuestStatus,
control::{watch_events_reply::Event, ConsoleDataReply, ConsoleDataRequest},
},
};
use log::debug;
use tokio::{
@ -16,8 +19,6 @@ use tokio::{
use tokio_stream::{Stream, StreamExt};
use tonic::Streaming;
use crate::events::EventStream;
pub struct StdioConsoleStream;
impl StdioConsoleStream {

View File

@ -1,5 +1,3 @@
pub mod cli;
pub mod client;
pub mod console;
pub mod events;
pub mod format;

View File

@ -105,6 +105,7 @@ impl ControlService for RuntimeControlService {
network: None,
exit_info: None,
error_info: None,
domid: u32::MAX,
}),
spec: Some(spec),
}),

View File

@ -124,6 +124,7 @@ impl DaemonEventGenerator {
network: guest.state.clone().unwrap_or_default().network,
exit_info: Some(GuestExitInfo { code }),
error_info: None,
domid: guest.state.clone().map(|x| x.domid).unwrap_or(u32::MAX),
});
self.guests.update(id, entry).await?;

View File

@ -8,7 +8,7 @@ use krata::v1::{
},
control::GuestChangedEvent,
};
use kratart::{launch::GuestLaunchRequest, Runtime};
use kratart::{launch::GuestLaunchRequest, GuestInfo, Runtime};
use log::{error, info, trace, warn};
use tokio::{select, sync::mpsc::Receiver, task::JoinHandle, time::sleep};
use uuid::Uuid;
@ -92,10 +92,7 @@ impl GuestReconciler {
} else {
state.status = GuestStatus::Started.into();
}
state.network = Some(GuestNetworkState {
ipv4: runtime.ipv4.map(|x| x.ip().to_string()).unwrap_or_default(),
ipv6: runtime.ipv6.map(|x| x.ip().to_string()).unwrap_or_default(),
});
state.network = Some(guestinfo_to_networkstate(runtime));
stored_guest.state = Some(state);
}
}
@ -187,6 +184,8 @@ impl GuestReconciler {
}
};
let task = spec.task.as_ref().cloned().unwrap_or_default();
let info = self
.runtime
.launch(GuestLaunchRequest {
@ -199,24 +198,22 @@ impl GuestReconciler {
image: &oci.image,
vcpus: spec.vcpus,
mem: spec.mem,
env: spec
.env
env: task
.environment
.iter()
.map(|x| (x.key.clone(), x.value.clone()))
.collect::<HashMap<_, _>>(),
run: empty_vec_optional(spec.run.clone()),
run: empty_vec_optional(task.command.clone()),
debug: false,
})
.await?;
info!("started guest {}", uuid);
guest.state = Some(GuestState {
status: GuestStatus::Started.into(),
network: Some(GuestNetworkState {
ipv4: info.ipv4.map(|x| x.ip().to_string()).unwrap_or_default(),
ipv6: info.ipv6.map(|x| x.ip().to_string()).unwrap_or_default(),
}),
network: Some(guestinfo_to_networkstate(&info)),
exit_info: None,
error_info: None,
domid: info.domid,
});
Ok(true)
}
@ -232,6 +229,7 @@ impl GuestReconciler {
network: None,
exit_info: None,
error_info: None,
domid: guest.state.as_ref().map(|x| x.domid).unwrap_or(u32::MAX),
});
Ok(true)
}
@ -244,3 +242,14 @@ fn empty_vec_optional<T>(value: Vec<T>) -> Option<Vec<T>> {
Some(value)
}
}
fn guestinfo_to_networkstate(info: &GuestInfo) -> GuestNetworkState {
GuestNetworkState {
guest_ipv4: info.guest_ipv4.map(|x| x.to_string()).unwrap_or_default(),
guest_ipv6: info.guest_ipv6.map(|x| x.to_string()).unwrap_or_default(),
guest_mac: info.guest_mac.as_ref().cloned().unwrap_or_default(),
gateway_ipv4: info.gateway_ipv4.map(|x| x.to_string()).unwrap_or_default(),
gateway_ipv6: info.gateway_ipv6.map(|x| x.to_string()).unwrap_or_default(),
gateway_mac: info.gateway_mac.as_ref().cloned().unwrap_or_default(),
}
}

View File

@ -1,6 +1,7 @@
use anyhow::{anyhow, Result};
use env_logger::Env;
use krataguest::init::GuestInit;
use krataguest::{death, init::GuestInit};
use log::error;
use std::env;
#[tokio::main]
@ -19,6 +20,9 @@ async fn main() -> Result<()> {
}
}
let mut guest = GuestInit::new();
guest.init().await?;
if let Err(error) = guest.init().await {
error!("failed to initialize guest: {}", error);
death(127).await?;
}
Ok(())
}

View File

@ -1,10 +1,10 @@
use std::time::Duration;
use crate::childwait::{ChildEvent, ChildWait};
use crate::{
childwait::{ChildEvent, ChildWait},
death,
};
use anyhow::Result;
use nix::{libc::c_int, unistd::Pid};
use tokio::{select, time::sleep};
use xenstore::{XsdClient, XsdInterface};
use nix::unistd::Pid;
use tokio::select;
pub struct GuestBackground {
child: Pid,
@ -35,19 +35,8 @@ impl GuestBackground {
async fn child_event(&mut self, event: ChildEvent) -> Result<()> {
if event.pid == self.child {
self.death(event.status).await?;
death(event.status).await?;
}
Ok(())
}
async fn death(&mut self, code: c_int) -> Result<()> {
let store = XsdClient::open().await?;
store
.write_string("krata/guest/exit-code", &code.to_string())
.await?;
drop(store);
loop {
sleep(Duration::from_secs(1)).await;
}
}
}

View File

@ -1,3 +1,20 @@
use std::{os::raw::c_int, time::Duration};
use anyhow::Result;
use tokio::time::sleep;
use xenstore::{XsdClient, XsdInterface};
pub mod background;
pub mod childwait;
pub mod init;
pub async fn death(code: c_int) -> Result<()> {
let store = XsdClient::open().await?;
store
.write_string("krata/guest/exit-code", &code.to_string())
.await?;
drop(store);
loop {
sleep(Duration::from_secs(1)).await;
}
}

View File

@ -13,15 +13,16 @@ clap = { workspace = true }
env_logger = { workspace = true }
etherparse = { workspace = true }
futures = { workspace = true }
krata = { path = "../krata" }
libc = { workspace = true }
log = { workspace = true }
rtnetlink = { workspace = true }
smoltcp = { workspace = true }
tonic = { workspace = true }
tokio = { workspace = true }
tokio-tun = { workspace = true }
udp-stream = { workspace = true }
uuid = { workspace = true }
xenstore = { path = "../xen/xenstore" }
[lib]
name = "kratanet"
@ -33,7 +34,3 @@ path = "bin/network.rs"
[[example]]
name = "ping"
path = "examples/ping.rs"
[[example]]
name = "autonet"
path = "examples/autonet.rs"

View File

@ -1,15 +1,22 @@
use std::str::FromStr;
use anyhow::Result;
use clap::Parser;
use env_logger::Env;
use krata::dial::ControlDialAddress;
use kratanet::NetworkService;
#[derive(Parser, Debug)]
struct NetworkArgs {}
struct NetworkArgs {
#[arg(short, long, default_value = "unix:///var/lib/krata/daemon.socket")]
connection: String,
}
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
#[tokio::main]
async fn main() -> Result<()> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let _ = NetworkArgs::parse();
let mut service = NetworkService::new().await?;
let args = NetworkArgs::parse();
let control_dial_address = ControlDialAddress::from_str(&args.connection)?;
let mut service = NetworkService::new(control_dial_address).await?;
service.watch().await
}

View File

@ -1,15 +0,0 @@
use std::time::Duration;
use anyhow::Result;
use kratanet::autonet::AutoNetworkCollector;
use tokio::time::sleep;
#[tokio::main]
async fn main() -> Result<()> {
let mut collector = AutoNetworkCollector::new().await?;
loop {
let changeset = collector.read_changes().await?;
println!("{:?}", changeset);
sleep(Duration::from_secs(2)).await;
}
}

View File

@ -1,11 +1,24 @@
use anyhow::{anyhow, Result};
use anyhow::Result;
use krata::{
events::EventStream,
v1::{
common::Guest,
control::{
control_service_client::ControlServiceClient, watch_events_reply::Event,
ListGuestsRequest, WatchEventsRequest,
},
},
};
use log::warn;
use smoltcp::wire::{EthernetAddress, Ipv4Cidr, Ipv6Cidr};
use std::{collections::HashMap, str::FromStr};
use std::{collections::HashMap, str::FromStr, time::Duration};
use tokio::{select, sync::broadcast::Receiver, time::sleep};
use tonic::transport::Channel;
use uuid::Uuid;
use xenstore::{XsdClient, XsdInterface, XsdTransaction};
pub struct AutoNetworkCollector {
client: XsdClient,
pub struct AutoNetworkWatcher {
control: ControlServiceClient<Channel>,
pub events: EventStream,
known: HashMap<Uuid, NetworkMetadata>,
}
@ -36,116 +49,88 @@ pub struct AutoNetworkChangeset {
pub removed: Vec<NetworkMetadata>,
}
impl AutoNetworkCollector {
pub async fn new() -> Result<AutoNetworkCollector> {
Ok(AutoNetworkCollector {
client: XsdClient::open().await?,
impl AutoNetworkWatcher {
pub async fn new(mut control: ControlServiceClient<Channel>) -> Result<AutoNetworkWatcher> {
let watch_events_response = control.watch_events(WatchEventsRequest {}).await?;
Ok(AutoNetworkWatcher {
control,
events: EventStream::open(watch_events_response.into_inner()).await?,
known: HashMap::new(),
})
}
pub async fn read(&mut self) -> Result<Vec<NetworkMetadata>> {
let mut networks = Vec::new();
let tx = self.client.transaction().await?;
for domid_string in tx.list("/local/domain").await? {
let Ok(domid) = domid_string.parse::<u32>() else {
let mut all_guests: HashMap<Uuid, Guest> = HashMap::new();
for guest in self
.control
.list_guests(ListGuestsRequest {})
.await?
.into_inner()
.guests
{
let Ok(uuid) = Uuid::from_str(&guest.id) else {
continue;
};
all_guests.insert(uuid, guest);
}
let mut networks: Vec<NetworkMetadata> = Vec::new();
for (uuid, guest) in &all_guests {
let Some(ref state) = guest.state else {
continue;
};
let dom_path = format!("/local/domain/{}", domid_string);
let Some(uuid_string) = tx.read_string(&format!("{}/krata/uuid", dom_path)).await?
else {
if state.domid == u32::MAX {
continue;
}
let Some(ref network) = state.network else {
continue;
};
let Ok(uuid) = uuid_string.parse::<Uuid>() else {
let Ok(guest_ipv4_cidr) = Ipv4Cidr::from_str(&network.guest_ipv4) else {
continue;
};
let Ok(guest) =
AutoNetworkCollector::read_network_side(uuid, &tx, &dom_path, "guest").await
else {
let Ok(guest_ipv6_cidr) = Ipv6Cidr::from_str(&network.guest_ipv6) else {
continue;
};
let Ok(gateway) =
AutoNetworkCollector::read_network_side(uuid, &tx, &dom_path, "gateway").await
else {
let Ok(guest_mac) = EthernetAddress::from_str(&network.guest_mac) else {
continue;
};
let Ok(gateway_ipv4_cidr) = Ipv4Cidr::from_str(&network.gateway_ipv4) else {
continue;
};
let Ok(gateway_ipv6_cidr) = Ipv6Cidr::from_str(&network.gateway_ipv6) else {
continue;
};
let Ok(gateway_mac) = EthernetAddress::from_str(&network.gateway_mac) else {
continue;
};
networks.push(NetworkMetadata {
domid,
uuid,
guest,
gateway,
domid: state.domid,
uuid: *uuid,
guest: NetworkSide {
ipv4: guest_ipv4_cidr,
ipv6: guest_ipv6_cidr,
mac: guest_mac,
},
gateway: NetworkSide {
ipv4: gateway_ipv4_cidr,
ipv6: gateway_ipv6_cidr,
mac: gateway_mac,
},
});
}
tx.commit().await?;
Ok(networks)
}
async fn read_network_side(
uuid: Uuid,
tx: &XsdTransaction,
dom_path: &str,
side: &str,
) -> Result<NetworkSide> {
let side_path = format!("{}/krata/network/{}", dom_path, side);
let Some(ipv4) = tx.read_string(&format!("{}/ipv4", side_path)).await? else {
return Err(anyhow!(
"krata domain {} is missing {} ipv4 network entry",
uuid,
side
));
};
let Some(ipv6) = tx.read_string(&format!("{}/ipv6", side_path)).await? else {
return Err(anyhow!(
"krata domain {} is missing {} ipv6 network entry",
uuid,
side
));
};
let Some(mac) = tx.read_string(&format!("{}/mac", side_path)).await? else {
return Err(anyhow!(
"krata domain {} is missing {} mac address entry",
uuid,
side
));
};
let Ok(ipv4) = Ipv4Cidr::from_str(&ipv4) else {
return Err(anyhow!(
"krata domain {} has invalid {} ipv4 network cidr entry: {}",
uuid,
side,
ipv4
));
};
let Ok(ipv6) = Ipv6Cidr::from_str(&ipv6) else {
return Err(anyhow!(
"krata domain {} has invalid {} ipv6 network cidr entry: {}",
uuid,
side,
ipv6
));
};
let Ok(mac) = EthernetAddress::from_str(&mac) else {
return Err(anyhow!(
"krata domain {} has invalid {} mac address entry: {}",
uuid,
side,
mac
));
};
Ok(NetworkSide { ipv4, ipv6, mac })
}
pub async fn read_changes(&mut self) -> Result<AutoNetworkChangeset> {
let mut seen: Vec<Uuid> = Vec::new();
let mut added: Vec<NetworkMetadata> = Vec::new();
@ -179,6 +164,27 @@ impl AutoNetworkCollector {
Ok(AutoNetworkChangeset { added, removed })
}
pub async fn wait(&mut self, receiver: &mut Receiver<Event>) -> Result<()> {
loop {
select! {
x = receiver.recv() => match x {
Ok(Event::GuestChanged(_)) => {
break;
},
Err(error) => {
warn!("failed to receive event: {}", error);
}
},
_ = sleep(Duration::from_secs(10)) => {
break;
}
};
}
Ok(())
}
pub fn mark_unknown(&mut self, uuid: Uuid) -> Result<bool> {
Ok(self.known.remove(&uuid).is_some())
}

View File

@ -1,11 +1,17 @@
use std::{collections::HashMap, time::Duration};
use anyhow::Result;
use autonet::{AutoNetworkChangeset, AutoNetworkCollector, NetworkMetadata};
use autonet::{AutoNetworkChangeset, AutoNetworkWatcher, NetworkMetadata};
use futures::{future::join_all, TryFutureExt};
use hbridge::HostBridge;
use krata::{
client::ControlClientProvider,
dial::ControlDialAddress,
v1::{common::Guest, control::control_service_client::ControlServiceClient},
};
use log::warn;
use tokio::{task::JoinHandle, time::sleep};
use tonic::transport::Channel;
use uuid::Uuid;
use vbridge::VirtualBridge;
@ -26,17 +32,22 @@ const HOST_BRIDGE_MTU: usize = 1500;
pub const EXTRA_MTU: usize = 20;
pub struct NetworkService {
pub control: ControlServiceClient<Channel>,
pub guests: HashMap<Uuid, Guest>,
pub backends: HashMap<Uuid, JoinHandle<()>>,
pub bridge: VirtualBridge,
pub hbridge: HostBridge,
}
impl NetworkService {
pub async fn new() -> Result<NetworkService> {
pub async fn new(control_address: ControlDialAddress) -> Result<NetworkService> {
let control = ControlClientProvider::dial(control_address).await?;
let bridge = VirtualBridge::new()?;
let hbridge =
HostBridge::new(HOST_BRIDGE_MTU + EXTRA_MTU, "krata0".to_string(), &bridge).await?;
Ok(NetworkService {
control,
guests: HashMap::new(),
backends: HashMap::new(),
bridge,
hbridge,
@ -46,18 +57,19 @@ impl NetworkService {
impl NetworkService {
pub async fn watch(&mut self) -> Result<()> {
let mut collector = AutoNetworkCollector::new().await?;
let mut watcher = AutoNetworkWatcher::new(self.control.clone()).await?;
let mut receiver = watcher.events.subscribe();
loop {
let changeset = collector.read_changes().await?;
self.process_network_changeset(&mut collector, changeset)
let changeset = watcher.read_changes().await?;
self.process_network_changeset(&mut watcher, changeset)
.await?;
sleep(Duration::from_secs(2)).await;
watcher.wait(&mut receiver).await?;
}
}
async fn process_network_changeset(
&mut self,
collector: &mut AutoNetworkCollector,
collector: &mut AutoNetworkWatcher,
changeset: AutoNetworkChangeset,
) -> Result<()> {
for removal in &changeset.removed {

View File

@ -20,7 +20,7 @@ impl NatHandlerContext {
}
pub async fn reclaim(&self) -> Result<()> {
self.reclaim_sender.try_send(self.key)?;
let _ = self.reclaim_sender.try_send(self.key);
Ok(())
}
}

View File

@ -266,6 +266,12 @@ impl AsyncRawSocketChannel {
if error.kind() == ErrorKind::WouldBlock {
continue;
}
// device no longer exists
if error.raw_os_error() == Some(6) {
break;
}
return Err(anyhow!("failed to read from raw socket: {}", error));
}
};

View File

@ -1,5 +1,5 @@
use std::collections::HashMap;
use std::net::IpAddr;
use std::net::{IpAddr, Ipv6Addr};
use std::{fs, net::Ipv4Addr, str::FromStr};
use advmac::MacAddr6;
@ -113,7 +113,7 @@ impl GuestLauncher {
];
let cmdline = cmdline_options.join(" ");
let container_mac_string = container_mac.to_string().replace('-', ":");
let guest_mac_string = container_mac.to_string().replace('-', ":");
let gateway_mac_string = gateway_mac.to_string().replace('-', ":");
let mut extra_keys = vec![
@ -140,7 +140,7 @@ impl GuestLauncher {
),
(
"krata/network/guest/mac".to_string(),
container_mac_string.clone(),
guest_mac_string.clone(),
),
(
"krata/network/gateway/ipv4".to_string(),
@ -182,7 +182,7 @@ impl GuestLauncher {
],
consoles: vec![],
vifs: vec![DomainNetworkInterface {
mac: &container_mac_string,
mac: &guest_mac_string,
mtu: 1500,
bridge: None,
script: None,
@ -199,14 +199,24 @@ impl GuestLauncher {
domid,
image: request.image.to_string(),
loops: vec![],
ipv4: Some(IpNetwork::new(
guest_ipv4: Some(IpNetwork::new(
IpAddr::V4(guest_ipv4),
ipv4_network_mask as u8,
)?),
ipv6: Some(IpNetwork::new(
guest_ipv6: Some(IpNetwork::new(
IpAddr::V6(guest_ipv6),
ipv6_network_mask as u8,
)?),
guest_mac: Some(guest_mac_string.clone()),
gateway_ipv4: Some(IpNetwork::new(
IpAddr::V4(Ipv4Addr::from_str(gateway_ipv4)?),
ipv4_network_mask as u8,
)?),
gateway_ipv6: Some(IpNetwork::new(
IpAddr::V6(Ipv6Addr::from_str(gateway_ipv6)?),
ipv4_network_mask as u8,
)?),
gateway_mac: Some(gateway_mac_string.clone()),
state: GuestState { exit_code: None },
}),
Err(error) => {

View File

@ -45,8 +45,12 @@ pub struct GuestInfo {
pub domid: u32,
pub image: String,
pub loops: Vec<ContainerLoopInfo>,
pub ipv4: Option<IpNetwork>,
pub ipv6: Option<IpNetwork>,
pub guest_ipv4: Option<IpNetwork>,
pub guest_ipv6: Option<IpNetwork>,
pub guest_mac: Option<String>,
pub gateway_ipv4: Option<IpNetwork>,
pub gateway_ipv6: Option<IpNetwork>,
pub gateway_mac: Option<String>,
pub state: GuestState,
}
@ -130,25 +134,57 @@ impl RuntimeContext {
.store
.read_string(&format!("{}/krata/loops", &dom_path))
.await?;
let ipv4 = self
let guest_ipv4 = self
.xen
.store
.read_string(&format!("{}/krata/network/guest/ipv4", &dom_path))
.await?;
let ipv6 = self
let guest_ipv6 = self
.xen
.store
.read_string(&format!("{}/krata/network/guest/ipv6", &dom_path))
.await?;
let guest_mac = self
.xen
.store
.read_string(&format!("{}/krata/network/guest/mac", &dom_path))
.await?;
let gateway_ipv4 = self
.xen
.store
.read_string(&format!("{}/krata/network/gateway/ipv4", &dom_path))
.await?;
let gateway_ipv6 = self
.xen
.store
.read_string(&format!("{}/krata/network/gateway/ipv6", &dom_path))
.await?;
let gateway_mac = self
.xen
.store
.read_string(&format!("{}/krata/network/gateway/mac", &dom_path))
.await?;
let ipv4 = if let Some(ipv4) = ipv4 {
IpNetwork::from_str(&ipv4).ok()
let guest_ipv4 = if let Some(guest_ipv4) = guest_ipv4 {
IpNetwork::from_str(&guest_ipv4).ok()
} else {
None
};
let ipv6 = if let Some(ipv6) = ipv6 {
IpNetwork::from_str(&ipv6).ok()
let guest_ipv6 = if let Some(guest_ipv6) = guest_ipv6 {
IpNetwork::from_str(&guest_ipv6).ok()
} else {
None
};
let gateway_ipv4 = if let Some(gateway_ipv4) = gateway_ipv4 {
IpNetwork::from_str(&gateway_ipv4).ok()
} else {
None
};
let gateway_ipv6 = if let Some(gateway_ipv6) = gateway_ipv6 {
IpNetwork::from_str(&gateway_ipv6).ok()
} else {
None
};
@ -173,8 +209,12 @@ impl RuntimeContext {
domid,
image,
loops,
ipv4,
ipv6,
guest_ipv4,
guest_ipv6,
guest_mac,
gateway_ipv4,
gateway_ipv6,
gateway_mac,
state,
});
}

View File

@ -23,7 +23,7 @@ build_and_run() {
if [ "${KRATA_BUILD_INITRD}" = "1" ]
then
TARGET_ARCH="$(./hack/build/arch.sh)"
./hack/initrd/build.sh -q
./hack/initrd/build.sh ${CARGO_BUILD_FLAGS}
sudo cp "target/initrd/initrd-${TARGET_ARCH}" "/var/lib/krata/guest/initrd"
fi
RUST_TARGET="$(./hack/build/target.sh)"

View File

@ -17,8 +17,8 @@ message GuestSpec {
GuestImageSpec image = 2;
uint32 vcpus = 3;
uint64 mem = 4;
repeated GuestEnvVar env = 5;
repeated string run = 6;
GuestTaskSpec task = 5;
repeated GuestSpecAnnotation annotations = 6;
}
message GuestImageSpec {
@ -31,7 +31,17 @@ message GuestOciImageSpec {
string image = 1;
}
message GuestEnvVar {
message GuestTaskSpec {
repeated GuestTaskSpecEnvVar environment = 1;
repeated string command = 2;
}
message GuestTaskSpecEnvVar {
string key = 1;
string value = 2;
}
message GuestSpecAnnotation {
string key = 1;
string value = 2;
}
@ -41,6 +51,7 @@ message GuestState {
GuestNetworkState network = 2;
GuestExitInfo exit_info = 3;
GuestErrorInfo error_info = 4;
uint32 domid = 5;
}
enum GuestStatus {
@ -54,8 +65,12 @@ enum GuestStatus {
}
message GuestNetworkState {
string ipv4 = 1;
string ipv6 = 2;
string guest_ipv4 = 1;
string guest_ipv6 = 2;
string guest_mac = 3;
string gateway_ipv4 = 4;
string gateway_ipv6 = 5;
string gateway_mac = 6;
}
message GuestExitInfo {