2024-03-27 02:54:39 +00:00
|
|
|
use anyhow::Result;
|
|
|
|
use krata::{
|
|
|
|
events::EventStream,
|
|
|
|
v1::{
|
|
|
|
common::Guest,
|
|
|
|
control::{
|
|
|
|
control_service_client::ControlServiceClient, watch_events_reply::Event,
|
2024-03-31 01:11:50 +00:00
|
|
|
ListGuestsRequest,
|
2024-03-27 02:54:39 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
use log::warn;
|
2024-02-12 14:24:38 +00:00
|
|
|
use smoltcp::wire::{EthernetAddress, Ipv4Cidr, Ipv6Cidr};
|
2024-03-27 02:54:39 +00:00
|
|
|
use std::{collections::HashMap, str::FromStr, time::Duration};
|
|
|
|
use tokio::{select, sync::broadcast::Receiver, time::sleep};
|
|
|
|
use tonic::transport::Channel;
|
2024-02-12 14:24:38 +00:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
2024-03-27 02:54:39 +00:00
|
|
|
pub struct AutoNetworkWatcher {
|
|
|
|
control: ControlServiceClient<Channel>,
|
|
|
|
pub events: EventStream,
|
2024-02-12 14:24:38 +00:00
|
|
|
known: HashMap<Uuid, NetworkMetadata>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct NetworkSide {
|
|
|
|
pub ipv4: Ipv4Cidr,
|
|
|
|
pub ipv6: Ipv6Cidr,
|
|
|
|
pub mac: EthernetAddress,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct NetworkMetadata {
|
|
|
|
pub domid: u32,
|
|
|
|
pub uuid: Uuid,
|
|
|
|
pub guest: NetworkSide,
|
|
|
|
pub gateway: NetworkSide,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl NetworkMetadata {
|
|
|
|
pub fn interface(&self) -> String {
|
|
|
|
format!("vif{}.20", self.domid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct AutoNetworkChangeset {
|
|
|
|
pub added: Vec<NetworkMetadata>,
|
|
|
|
pub removed: Vec<NetworkMetadata>,
|
|
|
|
}
|
|
|
|
|
2024-03-27 02:54:39 +00:00
|
|
|
impl AutoNetworkWatcher {
|
2024-03-31 01:11:50 +00:00
|
|
|
pub async fn new(control: ControlServiceClient<Channel>) -> Result<AutoNetworkWatcher> {
|
|
|
|
let client = control.clone();
|
2024-03-27 02:54:39 +00:00
|
|
|
Ok(AutoNetworkWatcher {
|
|
|
|
control,
|
2024-03-31 01:11:50 +00:00
|
|
|
events: EventStream::open(client).await?,
|
2024-02-12 14:24:38 +00:00
|
|
|
known: HashMap::new(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-02-23 04:37:53 +00:00
|
|
|
pub async fn read(&mut self) -> Result<Vec<NetworkMetadata>> {
|
2024-03-27 02:54:39 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
|
|
|
if state.domid == u32::MAX {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let Some(ref network) = state.network else {
|
2024-02-12 14:24:38 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
2024-03-27 02:54:39 +00:00
|
|
|
let Ok(guest_ipv4_cidr) = Ipv4Cidr::from_str(&network.guest_ipv4) else {
|
2024-02-12 14:24:38 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
2024-03-27 02:54:39 +00:00
|
|
|
let Ok(guest_ipv6_cidr) = Ipv6Cidr::from_str(&network.guest_ipv6) else {
|
2024-02-12 14:24:38 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
2024-03-27 02:54:39 +00:00
|
|
|
let Ok(guest_mac) = EthernetAddress::from_str(&network.guest_mac) else {
|
2024-02-12 14:24:38 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
2024-03-27 02:54:39 +00:00
|
|
|
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 {
|
2024-02-12 14:24:38 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
networks.push(NetworkMetadata {
|
2024-03-27 02:54:39 +00:00
|
|
|
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,
|
|
|
|
},
|
2024-02-12 14:24:38 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
Ok(networks)
|
|
|
|
}
|
|
|
|
|
2024-02-23 04:37:53 +00:00
|
|
|
pub async fn read_changes(&mut self) -> Result<AutoNetworkChangeset> {
|
2024-02-12 14:24:38 +00:00
|
|
|
let mut seen: Vec<Uuid> = Vec::new();
|
|
|
|
let mut added: Vec<NetworkMetadata> = Vec::new();
|
|
|
|
let mut removed: Vec<NetworkMetadata> = Vec::new();
|
|
|
|
|
2024-03-31 01:11:50 +00:00
|
|
|
let networks = match self.read().await {
|
|
|
|
Ok(networks) => networks,
|
|
|
|
Err(error) => {
|
|
|
|
warn!("failed to read network changes: {}", error);
|
|
|
|
return Ok(AutoNetworkChangeset { added, removed });
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
for network in networks {
|
2024-02-12 14:24:38 +00:00
|
|
|
seen.push(network.uuid);
|
|
|
|
if self.known.contains_key(&network.uuid) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let _ = self.known.insert(network.uuid, network.clone());
|
|
|
|
added.push(network);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut gone: Vec<Uuid> = Vec::new();
|
|
|
|
for uuid in self.known.keys() {
|
|
|
|
if seen.contains(uuid) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
gone.push(*uuid);
|
|
|
|
}
|
|
|
|
|
|
|
|
for uuid in &gone {
|
|
|
|
let Some(network) = self.known.remove(uuid) else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
removed.push(network);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(AutoNetworkChangeset { added, removed })
|
|
|
|
}
|
2024-02-13 10:03:28 +00:00
|
|
|
|
2024-03-27 02:54:39 +00:00
|
|
|
pub async fn wait(&mut self, receiver: &mut Receiver<Event>) -> Result<()> {
|
|
|
|
loop {
|
|
|
|
select! {
|
|
|
|
x = receiver.recv() => match x {
|
|
|
|
Ok(Event::GuestChanged(_)) => {
|
|
|
|
break;
|
|
|
|
},
|
|
|
|
|
2024-04-12 18:09:26 +00:00
|
|
|
Ok(_) => {},
|
|
|
|
|
2024-03-27 02:54:39 +00:00
|
|
|
Err(error) => {
|
|
|
|
warn!("failed to receive event: {}", error);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_ = sleep(Duration::from_secs(10)) => {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-02-13 10:03:28 +00:00
|
|
|
pub fn mark_unknown(&mut self, uuid: Uuid) -> Result<bool> {
|
|
|
|
Ok(self.known.remove(&uuid).is_some())
|
|
|
|
}
|
2024-02-12 14:24:38 +00:00
|
|
|
}
|