machine state work

This commit is contained in:
Christien Rioux 2025-01-01 16:31:17 -05:00
parent 1af7050632
commit c361dce995
4 changed files with 312 additions and 151 deletions

View File

@ -139,7 +139,7 @@ impl MachineRegistryInner {
}
};
break Ok(machine_state_id.0);
break Ok(machine_state_id.external_id());
}
}

View File

@ -1,60 +1,69 @@
use super::*;
#[derive(Debug)]
struct MachineStateInner {
/// The template generating this machine
generating_template: Option<TemplateStateId>,
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum MachineOrigin {
InitialConfig,
Direct,
Template(TemplateStateId),
}
#[derive(Debug, Clone)]
struct MachineStateFields {
/// The current network interfaces definition
interfaces: HashMap<String, MachineStateInterface>,
interfaces: imbl::HashMap<Arc<String>, MachineStateInterface>,
/// Capabilities to disable on this machine
disable_capabilities: Vec<String>,
disable_capabilities: imbl::Vector<String>,
/// If this machine is a bootstrap
bootstrap: bool,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct MachineStateInterface {
/// The network this interface belongs to
pub network_id: Option<NetworkStateId>,
/// The veilid NetworkInterface state
pub network_interface: NetworkInterface,
pub network_interface: Arc<NetworkInterface>,
}
#[derive(Debug)]
struct MachineStateUnlockedInner {
struct MachineStateImmutable {
/// The id of this machine
id: MachineStateId,
/// The name of this machine if it is named
opt_name: Option<String>,
/// Where this machine came for housekeeping purposes
origin: MachineOrigin,
}
#[derive(Debug, Clone)]
pub struct MachineState {
xxx convert to immutable state
unlocked_inner: Arc<MachineStateUnlockedInner>,
inner: Arc<Mutex<MachineStateInner>>,
immutable: Arc<MachineStateImmutable>,
fields: Arc<MachineStateFields>,
}
pub type MachineStateId = StateId<MachineState>;
impl MachineState {
pub fn new(id: MachineStateId, opt_name: Option<String>) -> Self {
pub fn new(id: MachineStateId, opt_name: Option<String>, origin: MachineOrigin) -> Self {
// Create a localhost interface for this machine
Self {
unlocked_inner: Arc::new(MachineStateUnlockedInner { id, opt_name }),
inner: Arc::new(Mutex::new(MachineStateInner {
generating_template: None,
interfaces: HashMap::new(),
disable_capabilities: Vec::new(),
immutable: Arc::new(MachineStateImmutable {
id,
opt_name,
origin,
}),
fields: Arc::new(MachineStateFields {
interfaces: imbl::HashMap::new(),
disable_capabilities: imbl::Vector::new(),
bootstrap: false,
})),
}),
}
}
pub fn release(&self, machine_registry_inner: &mut MachineRegistryInner) {
pub fn release(mut self, machine_registry_inner: &mut MachineRegistryInner) {
self.release_all_interfaces(machine_registry_inner);
let inner = self.inner.lock();
if let Some(generating_template) = inner.generating_template {
if let MachineOrigin::Template(generating_template) = self.immutable.origin {
let template_state = machine_registry_inner
.template_states_mut()
.get_state(generating_template)
@ -63,44 +72,40 @@ impl MachineState {
}
}
pub fn external_id(&self) -> MachineId {
self.unlocked_inner.id.0
pub fn set_disable_capabilities(&mut self, disable_capabilities: Vec<String>) {
self.fields = Arc::new(MachineStateFields {
disable_capabilities: disable_capabilities.into(),
..(*self.fields).clone()
});
}
pub fn set_generating_template(&self, generating_template: TemplateStateId) {
let mut inner = self.inner.lock();
inner.generating_template = Some(generating_template);
pub fn set_bootstrap(&mut self, bootstrap: bool) {
self.fields = Arc::new(MachineStateFields {
bootstrap,
..(*self.fields).clone()
});
}
pub fn set_disable_capabilities(&self, disable_capabilities: Vec<String>) {
let mut inner = self.inner.lock();
inner.disable_capabilities = disable_capabilities;
}
pub fn set_bootstrap(&self, bootstrap: bool) {
let mut inner = self.inner.lock();
inner.bootstrap = bootstrap
}
fn next_free_interface_name_inner(inner: &MachineStateInner) -> String {
fn next_free_interface_key(&self) -> Arc<String> {
let mut inum = 0usize;
loop {
let name = format!("vin{}", inum);
if !inner.interfaces.contains_key(&name) {
return name;
if !self.fields.interfaces.contains_key(&name) {
return Arc::new(name);
}
inum += 1;
}
}
pub fn allocate_interface(
&self,
opt_name: Option<String>,
&mut self,
interface_name: Option<String>,
opt_interface_flags: Option<InterfaceFlags>,
) -> MachineRegistryResult<String> {
let mut inner = self.inner.lock();
let name = opt_name.unwrap_or_else(|| Self::next_free_interface_name_inner(&*inner));
if inner.interfaces.contains_key(&name) {
) -> MachineRegistryResult<Arc<String>> {
let interface_key = interface_name
.map(Arc::new)
.unwrap_or_else(|| self.next_free_interface_key());
if self.fields.interfaces.contains_key(&interface_key) {
return Err(MachineRegistryError::DuplicateName);
}
let flags = opt_interface_flags.unwrap_or_else(|| InterfaceFlags {
@ -109,44 +114,50 @@ impl MachineState {
is_point_to_point: false,
has_default_route: true,
});
inner.interfaces.insert(
name.clone(),
let interfaces = self.fields.interfaces.update(
interface_key.clone(),
MachineStateInterface {
network_id: None,
network_interface: NetworkInterface {
name: name.clone(),
network_interface: Arc::new(NetworkInterface {
name: (*interface_key).clone(),
flags,
addrs: Vec::new(),
},
}),
},
);
Ok(name)
self.fields = Arc::new(MachineStateFields {
interfaces,
..(*self.fields).clone()
});
Ok(interface_key)
}
pub fn interfaces(&self) -> Vec<String> {
let mut intfs: Vec<String> = self.inner.lock().interfaces.keys().cloned().collect();
pub fn interfaces(&self) -> Vec<Arc<String>> {
let mut intfs: Vec<_> = self.fields.interfaces.keys().cloned().collect();
intfs.sort();
intfs
}
pub fn allocate_address_ipv4(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
interface: &str,
interface_name: &str,
opt_address: Option<Ipv4Addr>,
opt_address_flags: Option<AddressFlags>,
) -> MachineRegistryResult<Ifv4Addr> {
let mut inner = self.inner.lock();
let Some(intf) = inner.interfaces.get_mut(interface) else {
let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else {
return Err(MachineRegistryError::InvalidName);
};
// Get the network state
let Some(network_id) = intf.network_id else {
let Some(network_id) = machine_state_interface.network_id else {
return Err(MachineRegistryError::NetworkNotFound);
};
let network_state = machine_registry_inner
let mut network_state = machine_registry_inner
.network_states()
.get_state(network_id)?;
@ -158,6 +169,11 @@ impl MachineState {
opt_address,
)?;
// Update the network state
machine_registry_inner
.network_states_mut()
.set_state(network_state);
// Get address flags
let flags = opt_address_flags.unwrap_or_else(|| AddressFlags {
is_dynamic,
@ -165,31 +181,49 @@ impl MachineState {
is_preferred: true,
});
intf.network_interface.addrs.push(InterfaceAddress {
// Update interface addresses
let mut new_intf = (*machine_state_interface.network_interface).clone();
new_intf.addrs.push(InterfaceAddress {
if_addr: IfAddr::V4(ifv4_addr.clone()),
flags,
});
// Update interface
machine_state_interface.network_interface = Arc::new(new_intf);
// Update interfaces map
let interfaces = self
.fields
.interfaces
.update(interface_key, machine_state_interface);
// Update fields
self.fields = Arc::new(MachineStateFields {
interfaces,
..(*self.fields).clone()
});
Ok(ifv4_addr)
}
pub fn allocate_address_ipv6(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
interface: &str,
interface_name: &str,
opt_address: Option<Ipv6Addr>,
opt_address_flags: Option<AddressFlags>,
) -> MachineRegistryResult<Ifv6Addr> {
let mut inner = self.inner.lock();
let Some(intf) = inner.interfaces.get_mut(interface) else {
let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else {
return Err(MachineRegistryError::InvalidName);
};
// Get the network state
let Some(network_id) = intf.network_id else {
let Some(network_id) = machine_state_interface.network_id else {
return Err(MachineRegistryError::NetworkNotFound);
};
let network_state = machine_registry_inner
let mut network_state = machine_registry_inner
.network_states()
.get_state(network_id)?;
@ -200,6 +234,10 @@ impl MachineState {
OwnerTag::Machine(self.id()),
opt_address,
)?;
// Update the network state
machine_registry_inner
.network_states_mut()
.set_state(network_state);
// Get address flags
let flags = opt_address_flags.unwrap_or_else(|| AddressFlags {
@ -208,48 +246,98 @@ impl MachineState {
is_preferred: true,
});
intf.network_interface.addrs.push(InterfaceAddress {
// Update interface addresses
let mut new_intf = (*machine_state_interface.network_interface).clone();
new_intf.addrs.push(InterfaceAddress {
if_addr: IfAddr::V6(ifv6_addr.clone()),
flags,
});
// Update interface
machine_state_interface.network_interface = Arc::new(new_intf);
// Update interfaces map
let interfaces = self
.fields
.interfaces
.update(interface_key, machine_state_interface);
// Update fields
self.fields = Arc::new(MachineStateFields {
interfaces,
..(*self.fields).clone()
});
Ok(ifv6_addr)
}
pub fn attach_network(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
interface: &str,
interface_name: &str,
network_id: NetworkStateId,
) -> MachineRegistryResult<()> {
let mut inner = self.inner.lock();
let Some(intf) = inner.interfaces.get_mut(interface) else {
let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else {
return Err(MachineRegistryError::InvalidName);
};
if intf.network_id.is_some() {
self.detach_network(machine_registry_inner, interface);
if machine_state_interface.network_id.is_some() {
Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?;
}
intf.network_id = Some(network_id);
machine_state_interface.network_id = Some(network_id);
// Update interfaces map
let interfaces = self
.fields
.interfaces
.update(interface_key, machine_state_interface);
// Update fields
self.fields = Arc::new(MachineStateFields {
interfaces,
..(*self.fields).clone()
});
Ok(())
}
pub fn detach_network(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
interface: &str,
interface_name: &str,
) -> MachineRegistryResult<()> {
let mut inner = self.inner.lock();
Self::detach_network_inner(&mut *inner, machine_registry_inner, interface)
let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else {
return Err(MachineRegistryError::InvalidName);
};
Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?;
// Update interfaces map
let interfaces = self
.fields
.interfaces
.update(interface_key, machine_state_interface);
// Update fields
self.fields = Arc::new(MachineStateFields {
interfaces,
..(*self.fields).clone()
});
Ok(())
}
pub fn attached_network_interfaces(
&self,
network_id: NetworkStateId,
) -> MachineRegistryResult<Vec<String>> {
) -> MachineRegistryResult<Vec<Arc<String>>> {
let mut out = Vec::new();
let inner = self.inner.lock();
for intf in &inner.interfaces {
for intf in &self.fields.interfaces {
if intf.1.network_id == Some(network_id) {
out.push(intf.0.clone());
}
@ -258,22 +346,23 @@ impl MachineState {
}
pub fn release_address(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
interface: &str,
interface_name: &str,
address: IpAddr,
) -> MachineRegistryResult<()> {
let mut inner = self.inner.lock();
let Some(intf) = inner.interfaces.get_mut(interface) else {
let interface_key = Arc::new(interface_name.to_owned());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else {
return Err(MachineRegistryError::InvalidName);
};
let Some(network_id) = intf.network_id else {
let Some(network_id) = machine_state_interface.network_id else {
return Err(MachineRegistryError::NetworkNotFound);
};
// Get the network state
let network_state = machine_registry_inner
let mut network_state = machine_registry_inner
.network_states()
.get_state(network_id)?;
@ -283,92 +372,168 @@ impl MachineState {
IpAddr::V6(ipv6_addr) => network_state.release_address_v6(ipv6_addr)?,
};
// Update the network state
machine_registry_inner
.network_states_mut()
.set_state(network_state);
// Remove the address from the interface
intf.network_interface
let addrs: Vec<_> = machine_state_interface
.network_interface
.addrs
.retain(|x| x.if_addr().ip() != address);
.iter()
.filter(|x| x.if_addr().ip() != address)
.cloned()
.collect();
// Update network interface
machine_state_interface.network_interface = Arc::new(NetworkInterface {
addrs,
..(*machine_state_interface.network_interface).clone()
});
// Update interfaces map
let interfaces = self
.fields
.interfaces
.update(interface_key, machine_state_interface);
// Update fields
self.fields = Arc::new(MachineStateFields {
interfaces,
..(*self.fields).clone()
});
Ok(())
}
pub fn release_all_addresses(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
interface: &str,
interface_name: &str,
) -> MachineRegistryResult<()> {
let mut inner = self.inner.lock();
Self::release_all_addresses_inner(&mut *inner, machine_registry_inner, interface)
}
fn detach_network_inner(
inner: &mut MachineStateInner,
machine_registry_inner: &mut MachineRegistryInner,
interface: &str,
) -> MachineRegistryResult<()> {
Self::release_all_addresses_inner(inner, machine_registry_inner, interface)?;
let Some(intf) = inner.interfaces.get_mut(interface) else {
let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else {
return Err(MachineRegistryError::InvalidName);
};
intf.network_id = None;
Self::release_all_addresses_inner(machine_registry_inner, &mut machine_state_interface)?;
// Update interfaces map
let interfaces = self
.fields
.interfaces
.update(interface_key, machine_state_interface);
// Update fields
self.fields = Arc::new(MachineStateFields {
interfaces,
..(*self.fields).clone()
});
Ok(())
}
////////////////////////////////////////////////////////////////////////
fn detach_network_inner(
machine_registry_inner: &mut MachineRegistryInner,
machine_state_interface: &mut MachineStateInterface,
) -> MachineRegistryResult<()> {
Self::release_all_addresses_inner(machine_registry_inner, machine_state_interface)?;
machine_state_interface.network_id = None;
Ok(())
}
fn release_all_addresses_inner(
inner: &mut MachineStateInner,
machine_registry_inner: &mut MachineRegistryInner,
interface: &str,
machine_state_interface: &mut MachineStateInterface,
) -> MachineRegistryResult<()> {
let Some(intf) = inner.interfaces.get_mut(interface) else {
return Err(MachineRegistryError::InvalidName);
};
let Some(network_id) = intf.network_id else {
let Some(network_id) = machine_state_interface.network_id else {
return Ok(());
};
// Get the network state
let network_state = machine_registry_inner
let mut network_state = machine_registry_inner
.network_states()
.get_state(network_id)?;
// Release the addresses from the network
for addr in &intf.network_interface.addrs {
for addr in &machine_state_interface.network_interface.addrs {
match addr.if_addr.ip() {
IpAddr::V4(ipv4_addr) => network_state.release_address_v4(ipv4_addr)?,
IpAddr::V6(ipv6_addr) => network_state.release_address_v6(ipv6_addr)?,
};
}
// Update the network state
machine_registry_inner
.network_states_mut()
.set_state(network_state);
// Remove the addresses from the interface
intf.network_interface.addrs.clear();
let mut new_intf = (*machine_state_interface.network_interface).clone();
new_intf.addrs.clear();
// Update interface
machine_state_interface.network_interface = Arc::new(new_intf);
Ok(())
}
pub fn release_interface(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
interface: &str,
interface_name: &str,
) -> MachineRegistryResult<()> {
let mut inner = self.inner.lock();
Self::detach_network_inner(&mut *inner, machine_registry_inner, interface)?;
inner
.interfaces
.remove(interface)
.expect("interface must exist");
let interface_key = Arc::new(interface_name.to_string());
let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned()
else {
return Err(MachineRegistryError::InvalidName);
};
Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?;
// Update interfaces map
let interfaces = self.fields.interfaces.without(&interface_key);
// Update fields
self.fields = Arc::new(MachineStateFields {
interfaces,
..(*self.fields).clone()
});
Ok(())
}
pub fn release_all_interfaces(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
) -> MachineRegistryResult<()> {
let mut inner = self.inner.lock();
let interfaces: Vec<String> = inner.interfaces.keys().cloned().collect();
for interface in interfaces {
Self::release_all_addresses_inner(&mut *inner, machine_registry_inner, &interface)?;
let interface_names: Vec<String> = self
.fields
.interfaces
.keys()
.map(|x| (**x).clone())
.collect();
for interface_name in interface_names {
let interface_key = Arc::new(interface_name);
let Some(mut machine_state_interface) =
self.fields.interfaces.get(&interface_key).cloned()
else {
return Err(MachineRegistryError::InvalidName);
};
Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?;
}
inner.interfaces.clear();
// Update fields
self.fields = Arc::new(MachineStateFields {
interfaces: imbl::HashMap::new(),
..(*self.fields).clone()
});
Ok(())
}
@ -467,10 +632,10 @@ impl MachineState {
impl State for MachineState {
fn id(&self) -> StateId<Self> {
self.unlocked_inner.id.clone()
self.immutable.id.clone()
}
fn name(&self) -> Option<String> {
self.unlocked_inner.opt_name.clone()
self.immutable.opt_name.clone()
}
}

View File

@ -148,18 +148,11 @@ impl NetworkState {
}
}
pub fn with_model(
self,
machine_registry_inner: &mut MachineRegistryInner,
params: NetworkStateModelParams,
) -> Self {
Self {
fields: Arc::new(NetworkStateFields {
model: NetworkStateModel { params },
..(*self.fields).clone()
}),
..self.clone()
}
pub fn set_model(&mut self, params: NetworkStateModelParams) {
self.fields = Arc::new(NetworkStateFields {
model: NetworkStateModel { params },
..(*self.fields).clone()
});
}
pub fn clear_ipv4(
@ -365,10 +358,6 @@ impl NetworkState {
Ok(())
}
pub fn set_generating_blueprint(&self, generating_blueprint: BlueprintStateId) {
inner.generating_blueprint = Some(generating_blueprint);
}
pub fn is_ipv4(&self) -> bool {
self.fields.lock().ipv4.is_some()
}
@ -396,7 +385,7 @@ impl NetworkState {
}
pub fn allocate_address_v4(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
owner_tag: OwnerTag,
opt_address: Option<Ipv4Addr>,
@ -447,16 +436,19 @@ impl NetworkState {
Self::can_allocate_net_v4_inner(&*inner, opt_address, prefix)
}
pub fn release_address_v4(&self, addr: Ipv4Addr) -> MachineRegistryResult<Option<OwnerTag>> {
pub fn release_address_v4(
&mut self,
addr: Ipv4Addr,
) -> MachineRegistryResult<Option<OwnerTag>> {
Self::release_subnet_v4_inner(&mut *inner, Ipv4Net::new(addr, 32).expect("must succeed"))
}
pub fn release_subnet_v4(&self, net: Ipv4Net) -> MachineRegistryResult<Option<OwnerTag>> {
pub fn release_subnet_v4(&mut self, net: Ipv4Net) -> MachineRegistryResult<Option<OwnerTag>> {
Self::release_subnet_v4_inner(&mut *inner, net)
}
pub fn allocate_address_v6(
&self,
&mut self,
machine_registry_inner: &mut MachineRegistryInner,
owner_tag: OwnerTag,
opt_address: Option<Ipv6Addr>,

View File

@ -14,6 +14,10 @@ impl<S: State> StateId<S> {
pub fn new(external_id: u64) -> Self {
Self(external_id, PhantomData {})
}
pub fn external_id(&self) -> u64 {
self.0
}
}
impl<S: State> Copy for StateId<S> {}