diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/machine_registry_inner.rs b/veilid-tools/src/virtual_network/router_server/machine_registry/machine_registry_inner.rs index 78bf825d..9a72db54 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/machine_registry_inner.rs +++ b/veilid-tools/src/virtual_network/router_server/machine_registry/machine_registry_inner.rs @@ -139,7 +139,7 @@ impl MachineRegistryInner { } }; - break Ok(machine_state_id.0); + break Ok(machine_state_id.external_id()); } } diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_state.rs b/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_state.rs index 46702676..5ef25392 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_state.rs +++ b/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_state.rs @@ -1,60 +1,69 @@ use super::*; -#[derive(Debug)] -struct MachineStateInner { - /// The template generating this machine - generating_template: Option, +#[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, + interfaces: imbl::HashMap, MachineStateInterface>, /// Capabilities to disable on this machine - disable_capabilities: Vec, + disable_capabilities: imbl::Vector, /// 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, /// The veilid NetworkInterface state - pub network_interface: NetworkInterface, + pub network_interface: Arc, } #[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, + /// Where this machine came for housekeeping purposes + origin: MachineOrigin, } #[derive(Debug, Clone)] pub struct MachineState { - xxx convert to immutable state - unlocked_inner: Arc, - inner: Arc>, + immutable: Arc, + fields: Arc, } pub type MachineStateId = StateId; impl MachineState { - pub fn new(id: MachineStateId, opt_name: Option) -> Self { + pub fn new(id: MachineStateId, opt_name: Option, 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) { + 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) { - 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 { 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, + &mut self, + interface_name: Option, opt_interface_flags: Option, - ) -> MachineRegistryResult { - 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> { + 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 { - let mut intfs: Vec = self.inner.lock().interfaces.keys().cloned().collect(); + pub fn interfaces(&self) -> Vec> { + 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, opt_address_flags: Option, ) -> 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); }; // 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, opt_address_flags: Option, ) -> 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); }; // 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> { + ) -> MachineRegistryResult>> { 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 = inner.interfaces.keys().cloned().collect(); - for interface in interfaces { - Self::release_all_addresses_inner(&mut *inner, machine_registry_inner, &interface)?; + let interface_names: Vec = 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.unlocked_inner.id.clone() + self.immutable.id.clone() } fn name(&self) -> Option { - self.unlocked_inner.opt_name.clone() + self.immutable.opt_name.clone() } } diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs b/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs index edce492b..6ffc4080 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs +++ b/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs @@ -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, @@ -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> { + pub fn release_address_v4( + &mut self, + addr: Ipv4Addr, + ) -> MachineRegistryResult> { Self::release_subnet_v4_inner(&mut *inner, Ipv4Net::new(addr, 32).expect("must succeed")) } - pub fn release_subnet_v4(&self, net: Ipv4Net) -> MachineRegistryResult> { + pub fn release_subnet_v4(&mut self, net: Ipv4Net) -> MachineRegistryResult> { 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, diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/state_allocator.rs b/veilid-tools/src/virtual_network/router_server/machine_registry/state/state_allocator.rs index fe2b9d89..07794448 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/state_allocator.rs +++ b/veilid-tools/src/virtual_network/router_server/machine_registry/state/state_allocator.rs @@ -14,6 +14,10 @@ impl StateId { pub fn new(external_id: u64) -> Self { Self(external_id, PhantomData {}) } + + pub fn external_id(&self) -> u64 { + self.0 + } } impl Copy for StateId {}