diff --git a/veilid-tools/src/bin/virtual_router/main.rs b/veilid-tools/src/bin/virtual_router/main.rs index 074ff3f3..56c045f5 100644 --- a/veilid-tools/src/bin/virtual_router/main.rs +++ b/veilid-tools/src/bin/virtual_router/main.rs @@ -78,7 +78,11 @@ fn main() -> Result<(), String> { return Ok(()); } - let router_server = virtual_network::RouterServer::new(initial_config); + let router_server = virtual_network::RouterServer::new(); + + if let Err(e) = router_server.execute_config(initial_config) { + xxx continue here + } let _ss_tcp = if !args.no_tcp { Some( diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/address_pool.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/address_pool.rs similarity index 91% rename from veilid-tools/src/virtual_network/router_server/machine_registry/address_pool.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/address_pool.rs index 50cc04cf..5965bb8a 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/address_pool.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/address_pool.rs @@ -58,9 +58,9 @@ impl AddressPool { false } - pub fn can_allocate_v6(&self, prefix: u8) -> MachineRegistryResult { + pub fn can_allocate_v6(&self, prefix: u8) -> GlobalStateManagerResult { if prefix > 128 { - return Err(MachineRegistryError::InvalidPrefix); + return Err(GlobalStateManagerError::InvalidPrefix(prefix)); } let mut srng = StableRng::new(0); @@ -68,9 +68,9 @@ impl AddressPool { Ok(opt_allocation.is_some()) } - pub fn can_allocate_v4(&self, prefix: u8) -> MachineRegistryResult { + pub fn can_allocate_v4(&self, prefix: u8) -> GlobalStateManagerResult { if prefix > 32 { - return Err(MachineRegistryError::InvalidPrefix); + return Err(GlobalStateManagerError::InvalidPrefix(prefix)); } let mut srng = StableRng::new(0); @@ -82,15 +82,15 @@ impl AddressPool { &mut self, allocation: Ipv4Net, opt_tag: Option, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { // Ensure the allocation is in our scope if !self.is_in_scope_v4(allocation) { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); } // Only reserve if it's not overlapping an allocation if !self.get_overlaps_v4(allocation).is_empty() { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); } // Add to our allocated pool @@ -104,15 +104,15 @@ impl AddressPool { &mut self, allocation: Ipv6Net, opt_tag: Option, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { // Ensure the allocation is in our scope if !self.is_in_scope_v6(allocation) { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); } // Only reserve if it's not overlapping an allocation if !self.get_overlaps_v6(allocation).is_empty() { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); } // Add to our allocated pool @@ -149,9 +149,9 @@ impl AddressPool { srng: &mut StableRng, prefix: u8, tag: T, - ) -> MachineRegistryResult> { + ) -> GlobalStateManagerResult> { if prefix > 32 { - return Err(MachineRegistryError::InvalidPrefix); + return Err(GlobalStateManagerError::InvalidPrefix(prefix)); } let opt_allocation = self.find_random_allocation_v4(srng, prefix); @@ -173,9 +173,9 @@ impl AddressPool { srng: &mut StableRng, prefix: u8, tag: T, - ) -> MachineRegistryResult> { + ) -> GlobalStateManagerResult> { if prefix > 128 { - return Err(MachineRegistryError::InvalidPrefix); + return Err(GlobalStateManagerError::InvalidPrefix(prefix)); } let opt_allocation = self.find_random_allocation_v6(srng, prefix); @@ -195,13 +195,13 @@ impl AddressPool { pub fn release_allocation_v4( &mut self, allocation: Ipv4Net, - ) -> MachineRegistryResult> { + ) -> GlobalStateManagerResult> { let Some(pos) = self.allocated_v4.iter().position(|x| *x == allocation) else { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); }; let Some(opt_tag) = self.owner_tags_v4.remove(&allocation) else { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); }; self.allocated_v4.remove(pos); @@ -212,13 +212,13 @@ impl AddressPool { pub fn release_allocation_v6( &mut self, allocation: Ipv6Net, - ) -> MachineRegistryResult> { + ) -> GlobalStateManagerResult> { let Some(pos) = self.allocated_v6.iter().position(|x| *x == allocation) else { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); }; let Some(opt_tag) = self.owner_tags_v6.remove(&allocation) else { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); }; self.allocated_v4.remove(pos); @@ -264,7 +264,7 @@ impl AddressPool { pub fn clear_ipv4 bool>( &mut self, mut check: F, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { if !self.is_ipv4() { return Ok(()); } @@ -272,7 +272,9 @@ impl AddressPool { IpNet::V4(ipv4_net) => check(ipv4_net, t), IpNet::V6(_ipv6_net) => false, }) { - return Err(MachineRegistryError::ResourceInUse); + return Err(GlobalStateManagerError::ResourceInUse( + "AddressPool-v4".to_owned(), + )); } assert!(self.owner_tags_v4.is_empty(), "tags should be empty"); self.scope_v4.clear(); @@ -284,7 +286,7 @@ impl AddressPool { pub fn clear_ipv6 bool>( &mut self, mut check: F, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { if !self.is_ipv6() { return Ok(()); } @@ -292,7 +294,9 @@ impl AddressPool { IpNet::V4(_ipv4_net) => false, IpNet::V6(ipv6_net) => check(ipv6_net, t), }) { - return Err(MachineRegistryError::ResourceInUse); + return Err(GlobalStateManagerError::ResourceInUse( + "AddressPool-v6".to_owned(), + )); } assert!(self.owner_tags_v6.is_empty(), "tags should be empty"); self.scope_v6.clear(); diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/machine_registry_inner.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/global_state_manager_inner.rs similarity index 83% rename from veilid-tools/src/virtual_network/router_server/machine_registry/machine_registry_inner.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/global_state_manager_inner.rs index 70d021bb..22af1c14 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/machine_registry_inner.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/global_state_manager_inner.rs @@ -1,73 +1,86 @@ use super::*; #[derive(Debug, Clone)] -pub(super) struct MachineRegistryInner { - unlocked_inner: Arc, +pub(super) struct GlobalStateManagerInner { + unlocked_inner: Arc, srng: StableRng, + models: imbl::HashMap, + allocations: imbl::HashMap, allocated_machines: imbl::HashSet, - profile_state_allocator: StateAllocator, - machine_state_allocator: StateAllocator, - template_state_allocator: StateAllocator, - network_state_allocator: StateAllocator, - blueprint_state_allocator: StateAllocator, + profile_state_registry: StateRegistry, + machine_state_registry: StateRegistry, + template_state_registry: StateRegistry, + network_state_registry: StateRegistry, + blueprint_state_registry: StateRegistry, } -impl MachineRegistryInner { +impl GlobalStateManagerInner { /////////////////////////////////////////////////////////// /// Public Interface - pub fn new(unlocked_inner: Arc) -> Self { - let srng = StableRng::new(unlocked_inner.config.seed.unwrap_or_default()); - - MachineRegistryInner { + pub fn new(unlocked_inner: Arc) -> Self { + GlobalStateManagerInner { unlocked_inner, - srng, + srng: StableRng::new(0), + models: imbl::HashMap::new(), + allocations: imbl::HashMap::new(), allocated_machines: imbl::HashSet::new(), - profile_state_allocator: StateAllocator::new(), - machine_state_allocator: StateAllocator::new(), - template_state_allocator: StateAllocator::new(), - network_state_allocator: StateAllocator::new(), - blueprint_state_allocator: StateAllocator::new(), + profile_state_registry: StateRegistry::new(), + machine_state_registry: StateRegistry::new(), + template_state_registry: StateRegistry::new(), + network_state_registry: StateRegistry::new(), + blueprint_state_registry: StateRegistry::new(), } } - pub fn srng(&mut self) -> &mut StableRng { - &mut self.srng - } - pub fn config(&self) -> &config::Config { - &self.unlocked_inner.config - } - pub fn execute_config(&self, cfg: config::Config) -> MachineRegistryResult<()> { - // Create all networks + pub fn execute_config(&mut self, cfg: config::Config) -> GlobalStateManagerResult<()> { + // Create random number generator + if let Some(seed) = cfg.seed { + self.srng = StableRng::new(seed); + } - // Create all blueprints + // Import all allocation definitions + for a in cfg.allocations { + if self.allocations.contains_key(&a.0) { + return Err(GlobalStateManagerError::DuplicateName(a.0)); + } + self.allocations.insert(a.0, a.1); + } - // Create all templates + // Import all models + for m in cfg.models { + if self.models.contains_key(&m.0) { + return Err(GlobalStateManagerError::DuplicateName(m.0)); + } + self.models.insert(m.0, m.1); + } - // Create all machines + // Create all profile states + + // Create all network states + + // Create all blueprint states + + // Create all template states + + // Create all machine states Ok(()) } - pub fn allocate(&mut self, profile: String) -> MachineRegistryResult { - // Get profile definition - let Some(profile_def) = self.unlocked_inner.config.profiles.get(&profile) else { - return Err(MachineRegistryError::ProfileNotFound); + pub fn allocate(&mut self, profile: String) -> GlobalStateManagerResult { + // Get current profile state + let Some(profile_state_id) = self.profile_state_registry.get_state_id_by_name(&profile) + else { + return Err(GlobalStateManagerError::ProfileNotFound(profile)); }; - // Get current profile state, creating one if we have not yet started executing the profile - let profile_state_id = self - .profile_state_allocator - .get_or_create_by_name(profile, |id, name| { - ProfileState::new(id, name, profile_def.clone()) - }); - // Get the next instance from the definition loop { // Move to the next profile instance let mut profile_state = self.profile_states().get_state(profile_state_id)?; let Some(instance_def) = profile_state.next_instance() else { - return Err(MachineRegistryError::ProfileComplete); + return Err(GlobalStateManagerError::ProfileComplete(profile)); }; self.profile_states_mut().set_state(profile_state); @@ -80,7 +93,7 @@ impl MachineRegistryInner { let Some(machine_state_id) = self.machine_states().get_state_id_by_name(name) else { - return Err(MachineRegistryError::MachineNotFound); + return Err(GlobalStateManagerError::MachineNotFound(name.clone())); }; if self.allocated_machines.contains(&machine_state_id) { Ok(None) @@ -109,7 +122,7 @@ impl MachineRegistryInner { let Some(template_state_id) = self.template_states().get_state_id_by_name(name) else { - return Err(MachineRegistryError::TemplateNotFound); + return Err(GlobalStateManagerError::TemplateNotFound(name.clone())); }; let template_state = self .template_states() @@ -143,7 +156,7 @@ impl MachineRegistryInner { } } - pub fn release(&mut self, machine_id: MachineId) -> MachineRegistryResult<()> { + pub fn release(&mut self, machine_id: MachineId) -> GlobalStateManagerResult<()> { let id = StateId::::new(machine_id); if self.allocated_machines.contains(&id) { // Was a fixed machine, so we leave the machine state so it can @@ -162,36 +175,47 @@ impl MachineRegistryInner { /////////////////////////////////////////////////////////// /// Private Implementation - pub(super) fn profile_states(&self) -> &StateAllocator { - &self.profile_state_allocator - } - pub(super) fn machine_states(&self) -> &StateAllocator { - &self.machine_state_allocator - } - pub(super) fn template_states(&self) -> &StateAllocator { - &self.template_state_allocator - } - pub(super) fn network_states(&self) -> &StateAllocator { - &self.network_state_allocator - } - pub(super) fn blueprint_states(&self) -> &StateAllocator { - &self.blueprint_state_allocator + pub(super) fn srng(&mut self) -> &mut StableRng { + &mut self.srng } - pub(super) fn profile_states_mut(&mut self) -> &mut StateAllocator { - &mut self.profile_state_allocator + pub(super) fn models(&self) -> &imbl::HashMap { + &self.models } - pub(super) fn machine_states_mut(&mut self) -> &mut StateAllocator { - &mut self.machine_state_allocator + pub(super) fn allocations(&self) -> &imbl::HashMap { + &self.allocations } - pub(super) fn template_states_mut(&mut self) -> &mut StateAllocator { - &mut self.template_state_allocator + + pub(super) fn profile_states(&self) -> &StateRegistry { + &self.profile_state_registry } - pub(super) fn network_states_mut(&mut self) -> &mut StateAllocator { - &mut self.network_state_allocator + pub(super) fn machine_states(&self) -> &StateRegistry { + &self.machine_state_registry } - pub(super) fn blueprint_states_mut(&mut self) -> &mut StateAllocator { - &mut self.blueprint_state_allocator + pub(super) fn template_states(&self) -> &StateRegistry { + &self.template_state_registry + } + pub(super) fn network_states(&self) -> &StateRegistry { + &self.network_state_registry + } + pub(super) fn blueprint_states(&self) -> &StateRegistry { + &self.blueprint_state_registry + } + + pub(super) fn profile_states_mut(&mut self) -> &mut StateRegistry { + &mut self.profile_state_registry + } + pub(super) fn machine_states_mut(&mut self) -> &mut StateRegistry { + &mut self.machine_state_registry + } + pub(super) fn template_states_mut(&mut self) -> &mut StateRegistry { + &mut self.template_state_registry + } + pub(super) fn network_states_mut(&mut self) -> &mut StateRegistry { + &mut self.network_state_registry + } + pub(super) fn blueprint_states_mut(&mut self) -> &mut StateRegistry { + &mut self.blueprint_state_registry } // pub(super) fn get_or_create_machine_state( diff --git a/veilid-tools/src/virtual_network/router_server/global_state_manager/mod.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/mod.rs new file mode 100644 index 00000000..911aaa0d --- /dev/null +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/mod.rs @@ -0,0 +1,117 @@ +mod address_pool; +mod global_state_manager_inner; +mod state; + +use super::*; + +use address_pool::*; +use global_state_manager_inner::*; +use state::*; + +#[derive(Debug)] +struct Machine {} + +#[derive(Debug)] +struct GlobalStateManagerUnlockedInner {} + +#[derive(Debug, Clone, ThisError, PartialEq, Eq)] +pub enum GlobalStateManagerError { + #[error("Invalid id: {0}")] + InvalidId(u64), + #[error("Invalid name: {0}")] + InvalidName(String), + #[error("Invalid prefix: {0}")] + InvalidPrefix(u8), + #[error("Already attached")] + AlreadyAttached, + #[error("Not attached")] + NotAttached, + #[error("Duplicate name: {0}")] + DuplicateName(String), + #[error("Profile complete: {0}")] + ProfileComplete(String), + #[error("Template complete: {0}")] + TemplateComplete(String), + #[error("Network complete: {0}")] + NetworkComplete(String), + #[error("Blueprint complete: {0}")] + BlueprintComplete(String), + #[error("Profile not found: {0}")] + ProfileNotFound(String), + #[error("Machine not found: {0}")] + MachineNotFound(String), + #[error("Network not found: {0}")] + NetworkNotFound(String), + #[error("Template not found: {0}")] + TemplateNotFound(String), + #[error("Blueprint not found: {0}")] + BlueprintNotFound(String), + #[error("Model not found: {0}")] + ModelNotFound(String), + #[error("No default model")] + NoDefaultModel, + #[error("No default network")] + NoDefaultNetwork, + #[error("No allocation available")] + NoAllocation, + #[error("Resource in use: {0}")] + ResourceInUse(String), +} + +pub type GlobalStateManagerResult = Result; + +#[derive(Debug, Clone)] +pub struct GlobalStateManager { + unlocked_inner: Arc, + inner: Arc>, +} + +impl GlobalStateManager { + /////////////////////////////////////////////////////////// + /// Public Interface + pub fn new() -> Self { + let unlocked_inner = Arc::new(GlobalStateManagerUnlockedInner {}); + Self { + inner: Arc::new(Mutex::new(GlobalStateManagerInner::new( + unlocked_inner.clone(), + ))), + unlocked_inner, + } + } + + pub fn execute_config(&self, cfg: config::Config) -> GlobalStateManagerResult<()> { + let mut inner = self.inner.lock(); + let saved_state = (*inner).clone(); + match inner.execute_config(cfg) { + Ok(v) => Ok(v), + Err(e) => { + *inner = saved_state; + Err(e) + } + } + } + + pub fn allocate(&self, profile: String) -> GlobalStateManagerResult { + let mut inner = self.inner.lock(); + let saved_state = (*inner).clone(); + match inner.allocate(profile) { + Ok(v) => Ok(v), + Err(e) => { + *inner = saved_state; + Err(e) + } + } + } + + pub fn release(&self, machine_id: MachineId) -> GlobalStateManagerResult<()> { + let mut inner = self.inner.lock(); + let saved_state = (*inner).clone(); + match inner.release(machine_id) { + Ok(v) => Ok(v), + Err(e) => { + *inner = saved_state; + Err(e) + } + } + } +} diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/blueprint_state.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/blueprint_state.rs similarity index 75% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/blueprint_state.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/blueprint_state.rs index 2c708cce..313e9111 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/blueprint_state.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/blueprint_state.rs @@ -69,7 +69,7 @@ pub struct BlueprintState { pub type BlueprintStateId = StateId; impl BlueprintState { - pub fn new(id: BlueprintStateId, name: String) -> MachineRegistryResult { + pub fn new(id: BlueprintStateId, name: String) -> GlobalStateManagerResult { Ok(Self { immutable: Arc::new(BlueprintStateImmutable { id, name }), fields: Arc::new(BlueprintStateFields { @@ -165,18 +165,18 @@ impl BlueprintState { }); } - pub fn is_active(&self, machine_registry_inner: &mut MachineRegistryInner) -> bool { + pub fn is_active(&self, gsm_inner: &mut GlobalStateManagerInner) -> bool { // Save a backup of the entire state - let backup = machine_registry_inner.clone(); + let backup = gsm_inner.clone(); // Make a copy of this blueprint state let mut current_state = self.clone(); // See what would happen if we try to generate this blueprint - let ok = current_state.generate(machine_registry_inner).is_ok(); + let ok = current_state.generate(gsm_inner).is_ok(); // Restore the backup - *machine_registry_inner = backup; + *gsm_inner = backup; // Return if this worked or not ok @@ -184,20 +184,16 @@ impl BlueprintState { fn generate_model_inner( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, network_state: &mut NetworkState, - ) -> MachineRegistryResult<()> { - let model_name = match self.fields.model.as_ref() { - Some(models) => (**machine_registry_inner.srng().weighted_choice_ref(models)).clone(), - None => machine_registry_inner - .config() - .default_model - .as_ref() - .ok_or(MachineRegistryError::NoDefaultModel)? - .clone(), + ) -> GlobalStateManagerResult<()> { + let Some(model_list) = self.fields.model.as_ref() else { + return Err(GlobalStateManagerError::NoDefaultModel); }; - let Some(model) = machine_registry_inner.config().models.get(&model_name) else { - return Err(MachineRegistryError::ModelNotFound); + let model_name = (**gsm_inner.srng().weighted_choice_ref(model_list)).clone(); + + let Some(model) = gsm_inner.models().get(&model_name) else { + return Err(GlobalStateManagerError::ModelNotFound(model_name)); }; let params = NetworkStateModelParams { @@ -212,13 +208,11 @@ impl BlueprintState { /// Network filter that ensures we can allocate an ipv4 gateway address on a network fn gateway_network_filter_v4( &self, - machine_registry_inner: &MachineRegistryInner, + gsm_inner: &GlobalStateManagerInner, network_state_id: NetworkStateId, - ) -> MachineRegistryResult { + ) -> GlobalStateManagerResult { // Get the network state - let network_state = machine_registry_inner - .network_states() - .get_state(network_state_id)?; + let network_state = gsm_inner.network_states().get_state(network_state_id)?; // See if we can allocate on this network let can_allocate = network_state.can_allocate_address_v4(None); @@ -229,13 +223,11 @@ impl BlueprintState { /// Network filter that ensures we can allocate an ipv4 gateway address on a network fn gateway_network_filter_v6( &self, - machine_registry_inner: &MachineRegistryInner, + gsm_inner: &GlobalStateManagerInner, network_state_id: NetworkStateId, - ) -> MachineRegistryResult { + ) -> GlobalStateManagerResult { // Get the network state - let network_state = machine_registry_inner - .network_states() - .get_state(network_state_id)?; + let network_state = gsm_inner.network_states().get_state(network_state_id)?; // See if we can allocate on this network let can_allocate = network_state.can_allocate_address_v6(None); @@ -245,19 +237,24 @@ impl BlueprintState { fn generate_ipv4_inner( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, network_state: &mut NetworkState, - ) -> MachineRegistryResult<()> { - network_state.clear_ipv4(machine_registry_inner)?; + ) -> GlobalStateManagerResult<()> { + network_state.clear_ipv4(gsm_inner)?; let Some(ipv4) = self.fields.ipv4.as_ref() else { return Ok(()); }; // Get addresses for network - let NetworkLocation { subnet, super_net } = ipv4 + let Some(NetworkLocation { subnet, super_net }) = ipv4 .params .locations - .pick_v4(machine_registry_inner, &ipv4.params.prefix)?; + .pick_v4(gsm_inner, &ipv4.params.prefix)? + else { + return Err(GlobalStateManagerError::BlueprintComplete( + self.debug_name(), + )); + }; let params = NetworkStateIpv4Params { allocation: subnet, @@ -266,35 +263,37 @@ impl BlueprintState { let gateway_params = match ipv4.gateway.as_ref() { Some(v4gw) => { - let translation = *machine_registry_inner + let translation = *gsm_inner .srng() .weighted_choice_ref(&v4gw.params.translation); - let upnp = machine_registry_inner - .srng() - .probability_test(v4gw.params.upnp); + let upnp = gsm_inner.srng().probability_test(v4gw.params.upnp); let (external_network, external_address) = match v4gw.params.locations.as_ref() { Some(locations_list) => { // A external network location was specified, pick one // Get a network to generate the machine on - let mut gateway_network_state = locations_list.pick( - machine_registry_inner, - |machine_registry_inner, id| { - self.gateway_network_filter_v4(machine_registry_inner, id) - }, - )?; + let Some(mut gateway_network_state) = locations_list + .pick(gsm_inner, |gsm_inner, id| { + self.gateway_network_filter_v4(gsm_inner, id) + })? + else { + return Err(GlobalStateManagerError::BlueprintComplete( + self.debug_name(), + )); + }; + let gateway_network_state_id = gateway_network_state.id(); // Allocate an external address on this network let external_interface_address = gateway_network_state .allocate_address_v4( - machine_registry_inner, + gsm_inner, OwnerTag::Gateway(network_state.id()), None, )?; // Update the network state - machine_registry_inner + gsm_inner .network_states_mut() .set_state(gateway_network_state); @@ -321,25 +320,30 @@ impl BlueprintState { None => None, }; - network_state.set_ipv4(machine_registry_inner, params, gateway_params)?; + network_state.set_ipv4(gsm_inner, params, gateway_params)?; Ok(()) } fn generate_ipv6_inner( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, network_state: &mut NetworkState, - ) -> MachineRegistryResult<()> { - network_state.clear_ipv6(machine_registry_inner)?; + ) -> GlobalStateManagerResult<()> { + network_state.clear_ipv6(gsm_inner)?; let Some(ipv6) = self.fields.ipv6.as_ref() else { return Ok(()); }; // Get addresses for network - let NetworkLocation { subnet, super_net } = ipv6 + let Some(NetworkLocation { subnet, super_net }) = ipv6 .params .locations - .pick_v6(machine_registry_inner, &ipv6.params.prefix)?; + .pick_v6(gsm_inner, &ipv6.params.prefix)? + else { + return Err(GlobalStateManagerError::BlueprintComplete( + self.debug_name(), + )); + }; let params = NetworkStateIpv6Params { allocation: subnet, @@ -348,35 +352,37 @@ impl BlueprintState { let gateway_params = match ipv6.gateway.as_ref() { Some(v6gw) => { - let translation = *machine_registry_inner + let translation = *gsm_inner .srng() .weighted_choice_ref(&v6gw.params.translation); - let upnp = machine_registry_inner - .srng() - .probability_test(v6gw.params.upnp); + let upnp = gsm_inner.srng().probability_test(v6gw.params.upnp); let (external_network, external_address) = match v6gw.params.locations.as_ref() { Some(locations_list) => { // A external network location was specified, pick one // Get a network to generate the machine on - let mut gateway_network_state = locations_list.pick( - machine_registry_inner, - |machine_registry_inner, id| { - self.gateway_network_filter_v6(machine_registry_inner, id) - }, - )?; + let Some(mut gateway_network_state) = locations_list + .pick(gsm_inner, |gsm_inner, id| { + self.gateway_network_filter_v6(gsm_inner, id) + })? + else { + return Err(GlobalStateManagerError::BlueprintComplete( + self.debug_name(), + )); + }; + let gateway_network_state_id = gateway_network_state.id(); // Allocate an external address on this network let external_interface_address = gateway_network_state .allocate_address_v6( - machine_registry_inner, + gsm_inner, OwnerTag::Gateway(network_state.id()), None, )?; // Update the network state - machine_registry_inner + gsm_inner .network_states_mut() .set_state(gateway_network_state); @@ -403,37 +409,39 @@ impl BlueprintState { None => None, }; - network_state.set_ipv6(machine_registry_inner, params, gateway_params)?; + network_state.set_ipv6(gsm_inner, params, gateway_params)?; Ok(()) } pub fn generate( &mut self, - machine_registry_inner: &mut MachineRegistryInner, - ) -> MachineRegistryResult { + gsm_inner: &mut GlobalStateManagerInner, + ) -> GlobalStateManagerResult { // See if there's room for another network if let Some(limit_network_count) = self.fields.limit_network_count { if self.fields.networks.len() >= limit_network_count { - return Err(MachineRegistryError::BlueprintComplete); + return Err(GlobalStateManagerError::BlueprintComplete( + self.debug_name(), + )); } } // Allocate a network id - let network_state_id = machine_registry_inner.network_states_mut().allocate_id(); + let network_state_id = gsm_inner.network_states_mut().allocate_id(); // Create an anonymous network state let mut network_state = NetworkState::new(network_state_id, None, NetworkOrigin::Blueprint(self.id())); if let Err(e) = (|| { - self.generate_model_inner(machine_registry_inner, &mut network_state)?; - self.generate_ipv4_inner(machine_registry_inner, &mut network_state)?; - self.generate_ipv6_inner(machine_registry_inner, &mut network_state)?; + self.generate_model_inner(gsm_inner, &mut network_state)?; + self.generate_ipv4_inner(gsm_inner, &mut network_state)?; + self.generate_ipv6_inner(gsm_inner, &mut network_state)?; Ok(()) })() { // Release the network state and id if things failed to allocate - network_state.release(machine_registry_inner); - machine_registry_inner + network_state.release(gsm_inner); + gsm_inner .network_states_mut() .release_id(network_state_id) .expect("must succeed"); @@ -441,9 +449,7 @@ impl BlueprintState { } // Attach the state to the id - machine_registry_inner - .network_states_mut() - .attach_state(network_state)?; + gsm_inner.network_states_mut().attach_state(network_state)?; // Record the newly instantiated network let mut networks = self.fields.networks.clone(); @@ -458,9 +464,9 @@ impl BlueprintState { Ok(network_state_id) } - pub fn for_each_network_id(&self, mut callback: F) -> MachineRegistryResult> + pub fn for_each_network_id(&self, mut callback: F) -> GlobalStateManagerResult> where - F: FnMut(NetworkStateId) -> MachineRegistryResult>, + F: FnMut(NetworkStateId) -> GlobalStateManagerResult>, { for network_id in &self.fields.networks { if let Some(res) = callback(*network_id)? { diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_locations_list.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_locations_list.rs similarity index 58% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_locations_list.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_locations_list.rs index e7787c05..d2d5025c 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_locations_list.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_locations_list.rs @@ -20,24 +20,19 @@ pub enum MachineLocationsList { impl MachineLocationsList { pub fn can_pick( &self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, mut network_filter: F, - ) -> MachineRegistryResult + ) -> GlobalStateManagerResult where - F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult, + F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult, { match self { MachineLocationsList::Networks { networks } => { // Filter the weighted list of networks to those that are still active and or not yet started if networks .try_filter(|id| { - let network_state = - machine_registry_inner.network_states().get_state(*id)?; - self.is_network_available( - machine_registry_inner, - network_state, - &mut network_filter, - ) + let network_state = gsm_inner.network_states().get_state(*id)?; + self.is_network_available(gsm_inner, network_state, &mut network_filter) })? .is_none() { @@ -48,15 +43,10 @@ impl MachineLocationsList { // Filter the weighted list of blueprints to those that are still active or not yet started and can allocate if blueprints .try_filter(|id| { - let blueprint_state = - machine_registry_inner.blueprint_states().get_state(*id)?; + let blueprint_state = gsm_inner.blueprint_states().get_state(*id)?; - self.is_blueprint_available( - machine_registry_inner, - blueprint_state, - &mut network_filter, - ) - .map(|x| x.is_some()) + self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter) + .map(|x| x.is_some()) })? .is_none() { @@ -69,20 +59,20 @@ impl MachineLocationsList { pub fn pick( &self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, mut network_filter: F, - ) -> MachineRegistryResult + ) -> GlobalStateManagerResult> where - F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult, + F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult, { // Get a network to generate the machine on let network_state = match self { MachineLocationsList::Networks { networks } => { // Filter the weighted list of networks to those that are still active and or not yet started let Some(available_networks) = networks.try_filter_map(|id| { - let network_state = machine_registry_inner.network_states().get_state(*id)?; + let network_state = gsm_inner.network_states().get_state(*id)?; if self.is_network_available( - machine_registry_inner, + gsm_inner, network_state.clone(), &mut network_filter, )? { @@ -92,13 +82,11 @@ impl MachineLocationsList { } })? else { - return Err(MachineRegistryError::NetworkComplete); + return Ok(None); }; // Weighted choice of network now that we have a candidate list - let network_state = machine_registry_inner - .srng() - .weighted_choice(available_networks); + let network_state = gsm_inner.srng().weighted_choice(available_networks); // Return network state to use network_state @@ -106,54 +94,42 @@ impl MachineLocationsList { MachineLocationsList::Blueprints { blueprints } => { // Filter the weighted list of blueprints to those that are still active or not yet started and can allocate let Some(available_blueprints) = blueprints.try_filter_map(|id| { - let blueprint_state = - machine_registry_inner.blueprint_states().get_state(*id)?; + let blueprint_state = gsm_inner.blueprint_states().get_state(*id)?; - self.is_blueprint_available( - machine_registry_inner, - blueprint_state, - &mut network_filter, - ) + self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter) })? else { - return Err(MachineRegistryError::BlueprintComplete); + return Ok(None); }; // Weighted choice of blueprint now that we have a candidate list - match machine_registry_inner - .srng() - .weighted_choice(available_blueprints) - { + match gsm_inner.srng().weighted_choice(available_blueprints) { BlueprintAvailability::Existing(network_state) => network_state, BlueprintAvailability::Generate(mut blueprint_state) => { // Generate network state from blueprint state - let network_state_id = blueprint_state.generate(machine_registry_inner)?; + let network_state_id = blueprint_state.generate(gsm_inner)?; // Update blueprint state - machine_registry_inner - .blueprint_states_mut() - .set_state(blueprint_state); + gsm_inner.blueprint_states_mut().set_state(blueprint_state); // Return network state - machine_registry_inner - .network_states() - .get_state(network_state_id)? + gsm_inner.network_states().get_state(network_state_id)? } } } }; - Ok(network_state) + Ok(Some(network_state)) } fn is_network_available( &self, - machine_registry_inner: &MachineRegistryInner, + gsm_inner: &GlobalStateManagerInner, network_state: NetworkState, mut network_filter: F, - ) -> MachineRegistryResult + ) -> GlobalStateManagerResult where - F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult, + F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult, { // If the network is not active, it is not available if !network_state.is_active()? { @@ -161,7 +137,7 @@ impl MachineLocationsList { } // Check the network filter - if !network_filter(machine_registry_inner, network_state.id())? { + if !network_filter(gsm_inner, network_state.id())? { return Ok(false); } @@ -170,23 +146,19 @@ impl MachineLocationsList { fn is_blueprint_available( &self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, blueprint_state: BlueprintState, mut network_filter: F, - ) -> MachineRegistryResult> + ) -> GlobalStateManagerResult> where - F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult, + F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult, { // See if the networks generated from this blueprint so far have availability // in this template if let Some(available_network_state) = blueprint_state.for_each_network_id(|id| { // Check the network's availability - let network_state = machine_registry_inner.network_states().get_state(id)?; - if self.is_network_available( - machine_registry_inner, - network_state.clone(), - &mut network_filter, - )? { + let network_state = gsm_inner.network_states().get_state(id)?; + if self.is_network_available(gsm_inner, network_state.clone(), &mut network_filter)? { // We found one return Ok(Some(network_state)); } @@ -200,7 +172,7 @@ impl MachineLocationsList { } // If the blueprint is active, it is available because it can make a new network - if blueprint_state.is_active(machine_registry_inner) { + if blueprint_state.is_active(gsm_inner) { return Ok(Some(BlueprintAvailability::Generate(blueprint_state))); } diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_state.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_state.rs similarity index 80% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_state.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_state.rs index 213dcc21..5ca4962b 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_state.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_state.rs @@ -60,17 +60,17 @@ impl MachineState { } } - pub fn release(mut self, machine_registry_inner: &mut MachineRegistryInner) { - self.release_all_interfaces(machine_registry_inner) + pub fn release(mut self, gsm_inner: &mut GlobalStateManagerInner) { + self.release_all_interfaces(gsm_inner) .expect("must succeed"); if let MachineOrigin::Template(generating_template) = self.immutable.origin { - let mut template_state = machine_registry_inner + let mut template_state = gsm_inner .template_states() .get_state(generating_template) .expect("must exist"); template_state.on_machine_released(self.id()); - machine_registry_inner + gsm_inner .template_states_mut() .set_state(template_state); } @@ -105,12 +105,14 @@ impl MachineState { &mut self, interface_name: Option, opt_interface_flags: Option, - ) -> MachineRegistryResult> { + ) -> GlobalStateManagerResult> { 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); + return Err(GlobalStateManagerError::DuplicateName( + (*interface_key).clone(), + )); } let flags = opt_interface_flags.unwrap_or(InterfaceFlags { is_loopback: false, @@ -146,35 +148,39 @@ impl MachineState { pub fn allocate_address_ipv4( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, interface_name: &str, opt_address: Option, opt_address_flags: Option, - ) -> MachineRegistryResult { + ) -> GlobalStateManagerResult { 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); + return Err(GlobalStateManagerError::InvalidName( + (*interface_key).clone(), + )); }; // Get the network state let Some(network_id) = machine_state_interface.network_id else { - return Err(MachineRegistryError::NetworkNotFound); + return Err(GlobalStateManagerError::NetworkNotFound( + (*interface_key).clone(), + )); }; - let mut network_state = machine_registry_inner + let mut network_state = gsm_inner .network_states() .get_state(network_id)?; // Allocate interface address let is_dynamic = opt_address.is_none(); let ifv4_addr = network_state.allocate_address_v4( - machine_registry_inner, + gsm_inner, OwnerTag::Machine(self.id()), opt_address, )?; // Update the network state - machine_registry_inner + gsm_inner .network_states_mut() .set_state(network_state); @@ -212,34 +218,38 @@ impl MachineState { pub fn allocate_address_ipv6( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, interface_name: &str, opt_address: Option, opt_address_flags: Option, - ) -> MachineRegistryResult { + ) -> GlobalStateManagerResult { 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); + return Err(GlobalStateManagerError::InvalidName( + (*interface_key).clone(), + )); }; // Get the network state let Some(network_id) = machine_state_interface.network_id else { - return Err(MachineRegistryError::NetworkNotFound); + return Err(GlobalStateManagerError::NetworkNotFound( + (*interface_key).clone(), + )); }; - let mut network_state = machine_registry_inner + let mut network_state = gsm_inner .network_states() .get_state(network_id)?; // Allocate interface address let is_dynamic = opt_address.is_none(); let ifv6_addr = network_state.allocate_address_v6( - machine_registry_inner, + gsm_inner, OwnerTag::Machine(self.id()), opt_address, )?; // Update the network state - machine_registry_inner + gsm_inner .network_states_mut() .set_state(network_state); @@ -277,18 +287,20 @@ impl MachineState { pub fn attach_network( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, interface_name: &str, network_id: NetworkStateId, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { 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); + return Err(GlobalStateManagerError::InvalidName( + (*interface_key).clone(), + )); }; if machine_state_interface.network_id.is_some() { - Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?; + Self::detach_network_inner(gsm_inner, &mut machine_state_interface)?; } machine_state_interface.network_id = Some(network_id); @@ -310,16 +322,18 @@ impl MachineState { pub fn detach_network( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, interface_name: &str, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { 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); + return Err(GlobalStateManagerError::InvalidName( + (*interface_key).clone(), + )); }; - Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?; + Self::detach_network_inner(gsm_inner, &mut machine_state_interface)?; // Update interfaces map let interfaces = self @@ -339,7 +353,7 @@ impl MachineState { pub fn attached_network_interfaces( &self, network_id: NetworkStateId, - ) -> MachineRegistryResult>> { + ) -> GlobalStateManagerResult>> { let mut out = Vec::new(); for intf in &self.fields.interfaces { if intf.1.network_id == Some(network_id) { @@ -351,22 +365,26 @@ impl MachineState { pub fn release_address( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, interface_name: &str, address: IpAddr, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { 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); + return Err(GlobalStateManagerError::InvalidName( + (*interface_key).clone(), + )); }; let Some(network_id) = machine_state_interface.network_id else { - return Err(MachineRegistryError::NetworkNotFound); + return Err(GlobalStateManagerError::NetworkNotFound( + (*interface_key).clone(), + )); }; // Get the network state - let mut network_state = machine_registry_inner + let mut network_state = gsm_inner .network_states() .get_state(network_id)?; @@ -377,7 +395,7 @@ impl MachineState { }; // Update the network state - machine_registry_inner + gsm_inner .network_states_mut() .set_state(network_state); @@ -413,16 +431,18 @@ impl MachineState { pub fn release_all_addresses( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, interface_name: &str, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { 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); + return Err(GlobalStateManagerError::InvalidName( + (*interface_key).clone(), + )); }; - Self::release_all_addresses_inner(machine_registry_inner, &mut machine_state_interface)?; + Self::release_all_addresses_inner(gsm_inner, &mut machine_state_interface)?; // Update interfaces map let interfaces = self @@ -442,24 +462,24 @@ impl MachineState { //////////////////////////////////////////////////////////////////////// fn detach_network_inner( - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, machine_state_interface: &mut MachineStateInterface, - ) -> MachineRegistryResult<()> { - Self::release_all_addresses_inner(machine_registry_inner, machine_state_interface)?; + ) -> GlobalStateManagerResult<()> { + Self::release_all_addresses_inner(gsm_inner, machine_state_interface)?; machine_state_interface.network_id = None; Ok(()) } fn release_all_addresses_inner( - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, machine_state_interface: &mut MachineStateInterface, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { let Some(network_id) = machine_state_interface.network_id else { return Ok(()); }; // Get the network state - let mut network_state = machine_registry_inner + let mut network_state = gsm_inner .network_states() .get_state(network_id)?; @@ -472,7 +492,7 @@ impl MachineState { } // Update the network state - machine_registry_inner + gsm_inner .network_states_mut() .set_state(network_state); @@ -488,16 +508,18 @@ impl MachineState { pub fn release_interface( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, interface_name: &str, - ) -> MachineRegistryResult<()> { + ) -> GlobalStateManagerResult<()> { 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); + return Err(GlobalStateManagerError::InvalidName( + (*interface_key).clone(), + )); }; - Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?; + Self::detach_network_inner(gsm_inner, &mut machine_state_interface)?; // Update interfaces map let interfaces = self.fields.interfaces.without(&interface_key); @@ -513,8 +535,8 @@ impl MachineState { pub fn release_all_interfaces( &mut self, - machine_registry_inner: &mut MachineRegistryInner, - ) -> MachineRegistryResult<()> { + gsm_inner: &mut GlobalStateManagerInner, + ) -> GlobalStateManagerResult<()> { let interface_names: Vec = self .fields .interfaces @@ -526,10 +548,12 @@ impl MachineState { let Some(mut machine_state_interface) = self.fields.interfaces.get(&interface_key).cloned() else { - return Err(MachineRegistryError::InvalidName); + return Err(GlobalStateManagerError::InvalidName( + (*interface_key).clone(), + )); }; - Self::detach_network_inner(machine_registry_inner, &mut machine_state_interface)?; + Self::detach_network_inner(gsm_inner, &mut machine_state_interface)?; } // Update fields diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/mod.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/mod.rs similarity index 88% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/mod.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/mod.rs index c6bc6b05..267f5f23 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/mod.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/mod.rs @@ -4,7 +4,7 @@ mod machine_state; mod network_locations_list; mod network_state; mod profile_state; -mod state_allocator; +mod state_registry; mod template_state; use super::*; @@ -15,5 +15,5 @@ pub use machine_state::*; pub use network_locations_list::*; pub use network_state::*; pub use profile_state::*; -pub use state_allocator::*; +pub use state_registry::*; pub use template_state::*; diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_locations_list.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_locations_list.rs similarity index 68% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/network_locations_list.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_locations_list.rs index a7ff021c..259d7632 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_locations_list.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_locations_list.rs @@ -20,9 +20,9 @@ pub struct NetworkLocation { impl NetworkLocationsList { pub fn pick_v4( &self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, prefix: &WeightedList, - ) -> MachineRegistryResult> { + ) -> GlobalStateManagerResult>> { // Get maximum prefix let max_prefix = prefix .iter() @@ -36,9 +36,8 @@ impl NetworkLocationsList { // Get allocations which have subnets that would fit // our maximum requested prefix let Some(alloc_subnets) = allocations.try_filter_map(|allocation_name| { - let allocation = machine_registry_inner - .config() - .allocations + let allocation = gsm_inner + .allocations() .get(allocation_name) .expect("must exist"); Ok(allocation @@ -48,48 +47,42 @@ impl NetworkLocationsList { .and_then(|subnet| subnet.filter(|p| p.prefix_len() <= max_prefix))) })? else { - return Err(MachineRegistryError::NoAllocation); + return Ok(None); }; // Pick an allocation - let subnets = machine_registry_inner - .srng() - .weighted_choice_ref(&alloc_subnets); + let subnets = gsm_inner.srng().weighted_choice_ref(&alloc_subnets); // Pick a subnet - let net = *machine_registry_inner.srng().weighted_choice_ref(subnets); + let net = *gsm_inner.srng().weighted_choice_ref(subnets); // Pick a prefix length that would fit in the subnet let opt_subnet = prefix .filter(|p| *p >= net.prefix_len()) .as_ref() .map(|wl| { - let subnet_prefix = *machine_registry_inner.srng().weighted_choice_ref(wl); + let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl); // Use an address pool temporarily to pick a subnet let mut address_pool = AddressPool::<()>::new(); address_pool.add_scope_v4(net); - address_pool.allocate_random_v4( - machine_registry_inner.srng(), - subnet_prefix, - (), - ) + address_pool.allocate_random_v4(gsm_inner.srng(), subnet_prefix, ()) }) .transpose()? .flatten(); let Some(subnet) = opt_subnet else { - return Err(MachineRegistryError::NoAllocation); + return Ok(None); }; - Ok(NetworkLocation { + Ok(Some(NetworkLocation { subnet, super_net: None, - }) + })) } NetworkLocationsList::Networks { networks } => { // Get networks which have subnets that would fit // our maximum requested prefix let Some(available_networks) = networks.try_filter(|network_id| { - let super_network_state = machine_registry_inner + let super_network_state = gsm_inner .network_states() .get_state(*network_id) .expect("must exist"); @@ -97,14 +90,12 @@ impl NetworkLocationsList { Ok(super_network_state.can_allocate_subnet_v4(None, max_prefix)) })? else { - return Err(MachineRegistryError::NoAllocation); + return Ok(None); }; // Pick a network - let super_network_id = *machine_registry_inner - .srng() - .weighted_choice_ref(&available_networks); - let mut super_network_state = machine_registry_inner + let super_network_id = *gsm_inner.srng().weighted_choice_ref(&available_networks); + let mut super_network_state = gsm_inner .network_states() .get_state(super_network_id) .expect("must exist"); @@ -114,11 +105,11 @@ impl NetworkLocationsList { .filter(|p| super_network_state.can_allocate_subnet_v4(None, *p)) .as_ref() .map(|wl| { - let subnet_prefix = *machine_registry_inner.srng().weighted_choice_ref(wl); + let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl); // Allocate subnet from this network super_network_state.allocate_subnet_v4( - machine_registry_inner, + gsm_inner, OwnerTag::Network(super_network_state.id()), None, subnet_prefix, @@ -126,27 +117,27 @@ impl NetworkLocationsList { }) .transpose()?; let Some(subnet) = opt_subnet else { - return Err(MachineRegistryError::NoAllocation); + return Ok(None); }; // Update network state - machine_registry_inner + gsm_inner .network_states_mut() .set_state(super_network_state); - Ok(NetworkLocation { + Ok(Some(NetworkLocation { subnet, super_net: Some(super_network_id), - }) + })) } } } pub fn pick_v6( &self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, prefix: &WeightedList, - ) -> MachineRegistryResult> { + ) -> GlobalStateManagerResult>> { // Get maximum prefix let max_prefix = prefix .iter() @@ -160,9 +151,8 @@ impl NetworkLocationsList { // Get allocations which have subnets that would fit // our maximum requested prefix let Some(alloc_subnets) = allocations.try_filter_map(|allocation_name| { - let allocation = machine_registry_inner - .config() - .allocations + let allocation = gsm_inner + .allocations() .get(allocation_name) .expect("must exist"); Ok(allocation @@ -172,48 +162,42 @@ impl NetworkLocationsList { .and_then(|subnet| subnet.filter(|p| p.prefix_len() <= max_prefix))) })? else { - return Err(MachineRegistryError::NoAllocation); + return Ok(None); }; // Pick an allocation - let subnets = machine_registry_inner - .srng() - .weighted_choice_ref(&alloc_subnets); + let subnets = gsm_inner.srng().weighted_choice_ref(&alloc_subnets); // Pick a subnet - let net = *machine_registry_inner.srng().weighted_choice_ref(subnets); + let net = *gsm_inner.srng().weighted_choice_ref(subnets); // Pick a prefix length that would fit in the subnet let opt_subnet = prefix .filter(|p| *p >= net.prefix_len()) .as_ref() .map(|wl| { - let subnet_prefix = *machine_registry_inner.srng().weighted_choice_ref(wl); + let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl); // Use an address pool temporarily to pick a subnet let mut address_pool = AddressPool::<()>::new(); address_pool.add_scope_v6(net); - address_pool.allocate_random_v6( - machine_registry_inner.srng(), - subnet_prefix, - (), - ) + address_pool.allocate_random_v6(gsm_inner.srng(), subnet_prefix, ()) }) .transpose()? .flatten(); let Some(subnet) = opt_subnet else { - return Err(MachineRegistryError::NoAllocation); + return Ok(None); }; - Ok(NetworkLocation { + Ok(Some(NetworkLocation { subnet, super_net: None, - }) + })) } NetworkLocationsList::Networks { networks } => { // Get networks which have subnets that would fit // our maximum requested prefix let Some(available_networks) = networks.try_filter(|network_id| { - let super_network_state = machine_registry_inner + let super_network_state = gsm_inner .network_states() .get_state(*network_id) .expect("must exist"); @@ -221,14 +205,12 @@ impl NetworkLocationsList { Ok(super_network_state.can_allocate_subnet_v6(None, max_prefix)) })? else { - return Err(MachineRegistryError::NoAllocation); + return Ok(None); }; // Pick a network - let super_network_id = *machine_registry_inner - .srng() - .weighted_choice_ref(&available_networks); - let mut super_network_state = machine_registry_inner + let super_network_id = *gsm_inner.srng().weighted_choice_ref(&available_networks); + let mut super_network_state = gsm_inner .network_states() .get_state(super_network_id) .expect("must exist"); @@ -238,11 +220,11 @@ impl NetworkLocationsList { .filter(|p| super_network_state.can_allocate_subnet_v6(None, *p)) .as_ref() .map(|wl| { - let subnet_prefix = *machine_registry_inner.srng().weighted_choice_ref(wl); + let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl); // Allocate subnet from this network super_network_state.allocate_subnet_v6( - machine_registry_inner, + gsm_inner, OwnerTag::Network(super_network_state.id()), None, subnet_prefix, @@ -250,18 +232,18 @@ impl NetworkLocationsList { }) .transpose()?; let Some(subnet) = opt_subnet else { - return Err(MachineRegistryError::NoAllocation); + return Ok(None); }; // Update network state - machine_registry_inner + gsm_inner .network_states_mut() .set_state(super_network_state); - Ok(NetworkLocation { + Ok(Some(NetworkLocation { subnet, super_net: Some(super_network_id), - }) + })) } } } diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_state.rs similarity index 85% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_state.rs index b1673ba5..ce2c6aa6 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_state.rs @@ -137,14 +137,14 @@ impl NetworkState { } } - pub fn release(self, machine_registry_inner: &mut MachineRegistryInner) { + pub fn release(self, gsm_inner: &mut GlobalStateManagerInner) { if let NetworkOrigin::Blueprint(generating_blueprint) = self.immutable.origin { - let mut blueprint_state = machine_registry_inner + let mut blueprint_state = gsm_inner .blueprint_states() .get_state(generating_blueprint) .expect("must exist"); blueprint_state.on_network_released(self.id()); - machine_registry_inner + gsm_inner .blueprint_states_mut() .set_state(blueprint_state) } @@ -159,25 +159,29 @@ impl NetworkState { pub fn clear_ipv4( &mut self, - machine_registry_inner: &mut MachineRegistryInner, - ) -> MachineRegistryResult<()> { + gsm_inner: &mut GlobalStateManagerInner, + ) -> GlobalStateManagerResult<()> { let Some(ipv4) = self.fields.ipv4.clone() else { return Ok(()); }; let mut address_pool = self.fields.address_pool.clone(); - address_pool.clear_ipv4(|_n, t| match t { - OwnerTag::Machine(_) => true, - OwnerTag::Network(nsid) => *nsid != self.id(), - OwnerTag::Gateway(nsid) => *nsid != self.id(), - })?; + address_pool + .clear_ipv4(|_n, t| match t { + OwnerTag::Machine(_) => true, + OwnerTag::Network(nsid) => *nsid != self.id(), + OwnerTag::Gateway(nsid) => *nsid != self.id(), + }) + .map_err(|_| { + GlobalStateManagerError::ResourceInUse(format!("{}-v4", self.debug_name())) + })?; // If we have a gateway, release its external address // if it belongs to a different network if let Some(gateway) = ipv4.gateway.as_ref() { if gateway.params.external_network != self.id() { // Get the external network state - let mut external_network_state = machine_registry_inner + let mut external_network_state = gsm_inner .network_states() .get_state(gateway.params.external_network) .expect("must succeed"); @@ -188,7 +192,7 @@ impl NetworkState { .expect("must succeed"); // Update external network - machine_registry_inner + gsm_inner .network_states_mut() .set_state(external_network_state); } @@ -206,11 +210,11 @@ impl NetworkState { pub fn set_ipv4( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, params: NetworkStateIpv4Params, gateway_params: Option, - ) -> MachineRegistryResult<()> { - self.clear_ipv4(machine_registry_inner)?; + ) -> GlobalStateManagerResult<()> { + self.clear_ipv4(gsm_inner)?; let mut address_pool = self.fields.address_pool.clone(); address_pool.add_scope_v4(params.allocation); @@ -227,12 +231,12 @@ impl NetworkState { internal_address } else { let Some(internal_address) = address_pool.allocate_random_v4( - machine_registry_inner.srng(), + gsm_inner.srng(), 32, OwnerTag::Gateway(self.id()), )? else { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); }; internal_address.addr() }; @@ -245,7 +249,7 @@ impl NetworkState { }; // Get the external network state - let mut external_network_state = machine_registry_inner + let mut external_network_state = gsm_inner .network_states() .get_state(gateway_params.external_network) .expect("must succeed"); @@ -256,7 +260,7 @@ impl NetworkState { // If the translation mode is 'none', then the external and internal // addresses must be the same external_network_state.allocate_address_v4( - machine_registry_inner, + gsm_inner, OwnerTag::Gateway(self.id()), Some(internal_address), )? @@ -264,14 +268,14 @@ impl NetworkState { // Network translation means the internal and external addresses // will be different external_network_state.allocate_address_v4( - machine_registry_inner, + gsm_inner, OwnerTag::Gateway(self.id()), None, )? }; // Update external network - machine_registry_inner + gsm_inner .network_states_mut() .set_state(external_network_state); @@ -299,25 +303,29 @@ impl NetworkState { pub fn clear_ipv6( &mut self, - machine_registry_inner: &mut MachineRegistryInner, - ) -> MachineRegistryResult<()> { + gsm_inner: &mut GlobalStateManagerInner, + ) -> GlobalStateManagerResult<()> { let Some(ipv6) = self.fields.ipv6.clone() else { return Ok(()); }; let mut address_pool = self.fields.address_pool.clone(); - address_pool.clear_ipv6(|_n, t| match t { - OwnerTag::Machine(_) => true, - OwnerTag::Network(nsid) => *nsid != self.id(), - OwnerTag::Gateway(nsid) => *nsid != self.id(), - })?; + address_pool + .clear_ipv6(|_n, t| match t { + OwnerTag::Machine(_) => true, + OwnerTag::Network(nsid) => *nsid != self.id(), + OwnerTag::Gateway(nsid) => *nsid != self.id(), + }) + .map_err(|_| { + GlobalStateManagerError::ResourceInUse(format!("{}-v6", self.debug_name())) + })?; // If we have a gateway, release its external address // if it belongs to a different network if let Some(gateway) = ipv6.gateway.as_ref() { if gateway.params.external_network != self.id() { // Get the external network state - let mut external_network_state = machine_registry_inner + let mut external_network_state = gsm_inner .network_states() .get_state(gateway.params.external_network) .expect("must succeed"); @@ -328,7 +336,7 @@ impl NetworkState { .expect("must succeed"); // Update external network - machine_registry_inner + gsm_inner .network_states_mut() .set_state(external_network_state); } @@ -345,11 +353,11 @@ impl NetworkState { } pub fn set_ipv6( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, params: NetworkStateIpv6Params, gateway_params: Option, - ) -> MachineRegistryResult<()> { - self.clear_ipv6(machine_registry_inner)?; + ) -> GlobalStateManagerResult<()> { + self.clear_ipv6(gsm_inner)?; let mut address_pool = self.fields.address_pool.clone(); address_pool.add_scope_v6(params.allocation); @@ -366,12 +374,12 @@ impl NetworkState { internal_address } else { let Some(internal_address) = address_pool.allocate_random_v6( - machine_registry_inner.srng(), + gsm_inner.srng(), 128, OwnerTag::Gateway(self.id()), )? else { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); }; internal_address.addr() }; @@ -384,7 +392,7 @@ impl NetworkState { }; // Get the external network state - let mut external_network_state = machine_registry_inner + let mut external_network_state = gsm_inner .network_states() .get_state(gateway_params.external_network) .expect("must succeed"); @@ -395,7 +403,7 @@ impl NetworkState { // If the translation mode is 'none', then the external and internal // addresses must be the same external_network_state.allocate_address_v6( - machine_registry_inner, + gsm_inner, OwnerTag::Gateway(self.id()), Some(internal_address), )? @@ -403,14 +411,14 @@ impl NetworkState { // Network translation means the internal and external addresses // will be different external_network_state.allocate_address_v6( - machine_registry_inner, + gsm_inner, OwnerTag::Gateway(self.id()), None, )? }; // Update external network - machine_registry_inner + gsm_inner .network_states_mut() .set_state(external_network_state); @@ -444,7 +452,7 @@ impl NetworkState { self.fields.ipv6.is_some() } - pub fn is_active(&self) -> MachineRegistryResult { + pub fn is_active(&self) -> GlobalStateManagerResult { let mut can_allocate = false; if self.fields.ipv4.is_some() { @@ -464,11 +472,11 @@ impl NetworkState { pub fn allocate_address_v4( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, owner_tag: OwnerTag, opt_address: Option, - ) -> MachineRegistryResult { - let net = self.allocate_subnet_v4(machine_registry_inner, owner_tag, opt_address, 32)?; + ) -> GlobalStateManagerResult { + let net = self.allocate_subnet_v4(gsm_inner, owner_tag, opt_address, 32)?; let ip = net.addr(); let ipv4 = self.fields.ipv4.as_ref().unwrap(); @@ -490,13 +498,13 @@ impl NetworkState { pub fn allocate_subnet_v4( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, owner_tag: OwnerTag, opt_address: Option, prefix: u8, - ) -> MachineRegistryResult { + ) -> GlobalStateManagerResult { if self.fields.ipv4.is_none() { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); } // See if we are requesting a specific address @@ -510,12 +518,12 @@ impl NetworkState { } else { // Get a random address if available let Some(allocation) = address_pool.allocate_random_v4( - machine_registry_inner.srng(), + gsm_inner.srng(), prefix, owner_tag, )? else { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); }; allocation }; @@ -551,11 +559,14 @@ impl NetworkState { pub fn release_address_v4( &mut self, addr: Ipv4Addr, - ) -> MachineRegistryResult> { + ) -> GlobalStateManagerResult> { self.release_subnet_v4(Ipv4Net::new(addr, 32).expect("must succeed")) } - pub fn release_subnet_v4(&mut self, net: Ipv4Net) -> MachineRegistryResult> { + pub fn release_subnet_v4( + &mut self, + net: Ipv4Net, + ) -> GlobalStateManagerResult> { let mut address_pool = self.fields.address_pool.clone(); let opt_tag = address_pool.release_allocation_v4(net)?; @@ -569,11 +580,11 @@ impl NetworkState { pub fn allocate_address_v6( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, owner_tag: OwnerTag, opt_address: Option, - ) -> MachineRegistryResult { - let net = self.allocate_subnet_v6(machine_registry_inner, owner_tag, opt_address, 128)?; + ) -> GlobalStateManagerResult { + let net = self.allocate_subnet_v6(gsm_inner, owner_tag, opt_address, 128)?; let ip = net.addr(); let ipv6 = self.fields.ipv6.as_ref().unwrap(); @@ -595,13 +606,13 @@ impl NetworkState { pub fn allocate_subnet_v6( &mut self, - machine_registry_inner: &mut MachineRegistryInner, + gsm_inner: &mut GlobalStateManagerInner, owner_tag: OwnerTag, opt_address: Option, prefix: u8, - ) -> MachineRegistryResult { + ) -> GlobalStateManagerResult { if self.fields.ipv6.is_none() { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); } // See if we are requesting a specific address @@ -615,12 +626,12 @@ impl NetworkState { } else { // Get a random address if available let Some(allocation) = address_pool.allocate_random_v6( - machine_registry_inner.srng(), + gsm_inner.srng(), prefix, owner_tag, )? else { - return Err(MachineRegistryError::NoAllocation); + return Err(GlobalStateManagerError::NoAllocation); }; allocation }; @@ -656,11 +667,14 @@ impl NetworkState { pub fn release_address_v6( &mut self, addr: Ipv6Addr, - ) -> MachineRegistryResult> { + ) -> GlobalStateManagerResult> { self.release_subnet_v6(Ipv6Net::new(addr, 128).expect("must succeed")) } - pub fn release_subnet_v6(&mut self, net: Ipv6Net) -> MachineRegistryResult> { + pub fn release_subnet_v6( + &mut self, + net: Ipv6Net, + ) -> GlobalStateManagerResult> { let mut address_pool = self.fields.address_pool.clone(); let opt_tag = address_pool.release_allocation_v6(net)?; diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/profile_state.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/profile_state.rs similarity index 100% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/profile_state.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/profile_state.rs diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/resolves_to.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/resolves_to.rs similarity index 100% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/resolves_to.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/resolves_to.rs diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/state_allocator.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/state_registry.rs similarity index 81% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/state_allocator.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/state_registry.rs index e252921f..629d9c84 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/state_allocator.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/state_registry.rs @@ -4,6 +4,10 @@ use std::marker::PhantomData; pub trait State: fmt::Debug + Clone { fn id(&self) -> StateId; fn name(&self) -> Option; + fn debug_name(&self) -> String { + self.name() + .unwrap_or_else(|| format!("<{}>", self.id().external_id())) + } } type StateIdInternal = u64; @@ -44,14 +48,14 @@ impl core::hash::Hash for StateId { } #[derive(Debug, Clone)] -pub struct StateAllocator { +pub struct StateRegistry { state_id_by_name: imbl::HashMap, StateIdInternal>, state_by_id: imbl::HashMap>, next_state_id: StateIdInternal, free_state_ids: imbl::Vector, } -impl StateAllocator { +impl StateRegistry { pub fn new() -> Self { Self { state_id_by_name: imbl::HashMap::new(), @@ -90,10 +94,10 @@ impl StateAllocator { StateId(state_id, PhantomData {}) } - pub fn release_id(&mut self, id: StateId) -> MachineRegistryResult<()> { + pub fn release_id(&mut self, id: StateId) -> GlobalStateManagerResult<()> { // Remove id to state mapping let Some(old_opt_state) = self.state_by_id.remove(&id.0) else { - return Err(MachineRegistryError::InvalidId); + return Err(GlobalStateManagerError::InvalidId(id.external_id())); }; // Release state if it is attached @@ -112,24 +116,24 @@ impl StateAllocator { Ok(()) } - pub fn attach_state(&mut self, state: S) -> MachineRegistryResult<()> { + pub fn attach_state(&mut self, state: S) -> GlobalStateManagerResult<()> { // Get the id from the state let id = state.id(); // Get the allocator slot let Some(opt_state) = self.state_by_id.get_mut(&id.0) else { - return Err(MachineRegistryError::InvalidId); + return Err(GlobalStateManagerError::InvalidId(id.external_id())); }; // Ensure the state slot isn't attached already if opt_state.is_some() { - return Err(MachineRegistryError::AlreadyAttached); + return Err(GlobalStateManagerError::AlreadyAttached); } // Ensure the name isn't duplicated if let Some(name) = state.name() { if self.state_id_by_name.contains_key(&name) { - return Err(MachineRegistryError::DuplicateName); + return Err(GlobalStateManagerError::DuplicateName(name)); } // Register the named state self.state_id_by_name @@ -143,15 +147,15 @@ impl StateAllocator { Ok(()) } - pub fn detach_state(&mut self, id: StateId) -> MachineRegistryResult { + pub fn detach_state(&mut self, id: StateId) -> GlobalStateManagerResult { // Get the allocator slot let Some(opt_state) = self.state_by_id.get_mut(&id.0) else { - return Err(MachineRegistryError::InvalidId); + return Err(GlobalStateManagerError::InvalidId(id.external_id())); }; // Take the state out of the slot and ensure the state slot isn't detached already let Some(state) = opt_state.take() else { - return Err(MachineRegistryError::NotAttached); + return Err(GlobalStateManagerError::NotAttached); }; // Release the name if it exists @@ -166,13 +170,13 @@ impl StateAllocator { Ok(state) } - pub fn get_state(&self, id: StateId) -> MachineRegistryResult { + pub fn get_state(&self, id: StateId) -> GlobalStateManagerResult { // Get the allocator slot let Some(opt_state) = self.state_by_id.get(&id.0) else { - return Err(MachineRegistryError::InvalidId); + return Err(GlobalStateManagerError::InvalidId(id.external_id())); }; let Some(state) = opt_state else { - return Err(MachineRegistryError::NotAttached); + return Err(GlobalStateManagerError::NotAttached); }; Ok(state.clone()) } @@ -188,7 +192,7 @@ impl StateAllocator { } } -impl Default for StateAllocator { +impl Default for StateRegistry { fn default() -> Self { Self::new() } diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/template_state.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/template_state.rs similarity index 86% rename from veilid-tools/src/virtual_network/router_server/machine_registry/state/template_state.rs rename to veilid-tools/src/virtual_network/router_server/global_state_manager/state/template_state.rs index b8d3fa3f..2d4b6c4a 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/template_state.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/template_state.rs @@ -106,25 +106,25 @@ impl TemplateState { }); } - pub fn is_active(&self, machine_registry_inner: &mut MachineRegistryInner) -> bool { + pub fn is_active(&self, gsm_inner: &mut GlobalStateManagerInner) -> bool { // Save a backup of the entire state - let backup = machine_registry_inner.clone(); + let backup = gsm_inner.clone(); // Make a copy of this template state let mut current_state = self.clone(); // See what would happen if we try to generate this template - let ok = current_state.generate(machine_registry_inner).is_ok(); + let ok = current_state.generate(gsm_inner).is_ok(); // Restore the backup - *machine_registry_inner = backup; + *gsm_inner = backup; // Return if this worked or not ok } /// Network filter that keeps this template generation within per-network limits - fn network_filter(&self, network_state_id: NetworkStateId) -> MachineRegistryResult { + fn network_filter(&self, network_state_id: NetworkStateId) -> GlobalStateManagerResult { // Get the per network info let Some(pni) = self.fields.machines_per_network.get(&network_state_id) else { // If we haven't allocated anything in the network yet it is @@ -144,26 +144,28 @@ impl TemplateState { pub fn generate( &mut self, - machine_registry_inner: &mut MachineRegistryInner, - ) -> MachineRegistryResult { + gsm_inner: &mut GlobalStateManagerInner, + ) -> GlobalStateManagerResult { // See if we have reached our machine limit if let Some(limit_machine_count) = self.fields.limit_machine_count { if self.fields.machines.len() < limit_machine_count { - return Err(MachineRegistryError::TemplateComplete); + return Err(GlobalStateManagerError::TemplateComplete(self.debug_name())); } } // If existing networks are all full, we'd have to allocate one, see if we'd be able to do that let Some(locations_list) = self.fields.locations_list.as_ref() else { - return Err(MachineRegistryError::TemplateComplete); + return Err(GlobalStateManagerError::TemplateComplete(self.debug_name())); }; // Get a network to generate the machine on - let network_state = - locations_list.pick(machine_registry_inner, |_, x| self.network_filter(x))?; + let Some(network_state) = locations_list.pick(gsm_inner, |_, x| self.network_filter(x))? + else { + return Err(GlobalStateManagerError::TemplateComplete(self.debug_name())); + }; // Allocate a machine id - let machine_state_id = machine_registry_inner.machine_states_mut().allocate_id(); + let machine_state_id = gsm_inner.machine_states_mut().allocate_id(); // Create an anonymous machine state let mut machine_state = @@ -183,18 +185,18 @@ impl TemplateState { // Make the default route interface let vin0 = machine_state.allocate_interface(None, None)?; - machine_state.attach_network(machine_registry_inner, &vin0, network_state.id())?; + machine_state.attach_network(gsm_inner, &vin0, network_state.id())?; if network_state.is_ipv4() { - machine_state.allocate_address_ipv4(machine_registry_inner, &vin0, None, None)?; + machine_state.allocate_address_ipv4(gsm_inner, &vin0, None, None)?; } if network_state.is_ipv6() { - machine_state.allocate_address_ipv6(machine_registry_inner, &vin0, None, None)?; + machine_state.allocate_address_ipv6(gsm_inner, &vin0, None, None)?; } Ok(()) })() { // Release the machine state and id if things failed to allocate - machine_state.release(machine_registry_inner); - machine_registry_inner + machine_state.release(gsm_inner); + gsm_inner .machine_states_mut() .release_id(machine_state_id) .expect("must succeed"); @@ -202,7 +204,7 @@ impl TemplateState { } // Attach the state to the id - machine_registry_inner + gsm_inner .machine_states_mut() .attach_state(machine_state) .expect("must succeed"); @@ -217,7 +219,7 @@ impl TemplateState { .fields .limit_machines_per_network .as_ref() - .map(|wl| *machine_registry_inner.srng().weighted_choice_ref(wl)); + .map(|wl| *gsm_inner.srng().weighted_choice_ref(wl)); PerNetworkInfo { limit_machine_count, machines: imbl::HashSet::new(), diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/mod.rs b/veilid-tools/src/virtual_network/router_server/machine_registry/mod.rs deleted file mode 100644 index 883f14c3..00000000 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/mod.rs +++ /dev/null @@ -1,87 +0,0 @@ -mod address_pool; -mod machine_registry_inner; -mod state; - -use super::*; - -use address_pool::*; -use machine_registry_inner::*; -use state::*; - -#[derive(Debug)] -struct Machine {} - -#[derive(Debug)] -struct MachineRegistryUnlockedInner { - config: config::Config, -} - -#[derive(Debug, Clone)] -pub enum MachineRegistryError { - InvalidId, - InvalidName, - InvalidPrefix, - AlreadyAttached, - NotAttached, - DuplicateName, - ProfileComplete, - TemplateComplete, - NetworkComplete, - BlueprintComplete, - ProfileNotFound, - MachineNotFound, - NetworkNotFound, - TemplateNotFound, - BlueprintNotFound, - ModelNotFound, - NoDefaultModel, - NoDefaultNetwork, - NoAllocation, - ResourceInUse, -} - -pub type MachineRegistryResult = Result; - -#[derive(Debug, Clone)] -pub struct MachineRegistry { - inner: Arc>, - unlocked_inner: Arc, -} - -impl MachineRegistry { - /////////////////////////////////////////////////////////// - /// Public Interface - pub fn new(config: config::Config) -> Self { - let unlocked_inner = Arc::new(MachineRegistryUnlockedInner { config }); - Self { - inner: Arc::new(Mutex::new(MachineRegistryInner::new( - unlocked_inner.clone(), - ))), - unlocked_inner, - } - } - - pub fn allocate(&self, profile: String) -> MachineRegistryResult { - let mut inner = self.inner.lock(); - let saved_state = (*inner).clone(); - match inner.allocate(profile) { - Ok(v) => Ok(v), - Err(e) => { - *inner = saved_state; - Err(e) - } - } - } - - pub fn release(&self, machine_id: MachineId) -> MachineRegistryResult<()> { - let mut inner = self.inner.lock(); - let saved_state = (*inner).clone(); - match inner.release(machine_id) { - Ok(v) => Ok(v), - Err(e) => { - *inner = saved_state; - Err(e) - } - } - } -} diff --git a/veilid-tools/src/virtual_network/router_server/mod.rs b/veilid-tools/src/virtual_network/router_server/mod.rs index 42aec569..20d6d84e 100644 --- a/veilid-tools/src/virtual_network/router_server/mod.rs +++ b/veilid-tools/src/virtual_network/router_server/mod.rs @@ -1,12 +1,12 @@ pub mod config; -mod machine_registry; +mod global_state_manager; mod server_processor; mod stable_rng; mod weighted_list; use super::*; -use machine_registry::*; +use global_state_manager::*; use server_processor::*; use stable_rng::*; use weighted_list::*; @@ -26,6 +26,8 @@ pub enum RouterServerError { SerializationError(postcard::Error), #[error("IO Error: {0}")] IoError(io::ErrorKind), + #[error("State Error: {0}")] + StateError(global_state_manager::GlobalStateManagerError), } pub type RouterServerResult = Result; @@ -40,10 +42,10 @@ enum RunLoopEvent { #[derive(Debug)] struct RouterServerUnlockedInner { - config: config::Config, new_client_sender: flume::Sender>, new_client_receiver: flume::Receiver>, server_processor: ServerProcessor, + global_state_manager: GlobalStateManager, } #[derive(Debug)] @@ -60,69 +62,44 @@ pub struct RouterServer { inner: Arc>, } +impl Default for RouterServer { + fn default() -> Self { + Self::new() + } +} + impl RouterServer { //////////////////////////////////////////////////////////////////// // Public Interface /// Create a router server for virtual networking - pub fn new(config: config::Config) -> Self { + pub fn new() -> Self { // Make a channel to receive new clients let (new_client_sender, new_client_receiver) = flume::unbounded(); + // Make a machine registry to manage state + let global_state_manager = GlobalStateManager::new(); + // Make a server processor to handle messages - let server_processor = ServerProcessor::new(config.clone()); + let server_processor = ServerProcessor::new(global_state_manager.clone()); Self { unlocked_inner: Arc::new(RouterServerUnlockedInner { - config, new_client_sender, new_client_receiver, server_processor, + global_state_manager, }), inner: Arc::new(Mutex::new(RouterServerInner {})), } } - async fn process_connection(self, reader: R, writer: W) -> RunLoopEvent - where - R: AsyncRead + Send + Unpin, - W: AsyncWrite + Send + Unpin, - { - let framed_reader = FramedRead::new(reader, BytesCodec); - let framed_writer = FramedWrite::new(writer, BytesCodec); - - let (outbound_sender, outbound_receiver) = flume::unbounded(); - let outbound_fut = system_boxed( - outbound_receiver - .into_stream() - .map(|command| { - to_stdvec(&command) - .map_err(io::Error::other) - .map(Bytes::from) - }) - .forward(framed_writer), - ); - - let inbound_fut = system_boxed(framed_reader.try_for_each(|x| async { - let x = x; - let cmd = from_bytes::(&x).map_err(io::Error::other)?; - - self.unlocked_inner - .server_processor - .enqueue_command(cmd, outbound_sender.clone()); - - Ok(()) - })); - - let mut unord = FuturesUnordered::new(); - unord.push(outbound_fut); - unord.push(inbound_fut); - - if let Some(Err(e)) = unord.next().await { - error!("{}", e); - } - - RunLoopEvent::Done + /// Execute a config file on the global state manager + pub fn execute_config(&self, cfg: config::Config) -> RouterServerResult<()> { + self.unlocked_inner + .global_state_manager + .execute_config(cfg) + .map_err(RouterServerError::StateError) } /// Accept RouterClient connections on a TCP socket @@ -329,4 +306,46 @@ impl RouterServer { //////////////////////////////////////////////////////////////////// // Private Implementation + + async fn process_connection(self, reader: R, writer: W) -> RunLoopEvent + where + R: AsyncRead + Send + Unpin, + W: AsyncWrite + Send + Unpin, + { + let framed_reader = FramedRead::new(reader, BytesCodec); + let framed_writer = FramedWrite::new(writer, BytesCodec); + + let (outbound_sender, outbound_receiver) = flume::unbounded(); + let outbound_fut = system_boxed( + outbound_receiver + .into_stream() + .map(|command| { + to_stdvec(&command) + .map_err(io::Error::other) + .map(Bytes::from) + }) + .forward(framed_writer), + ); + + let inbound_fut = system_boxed(framed_reader.try_for_each(|x| async { + let x = x; + let cmd = from_bytes::(&x).map_err(io::Error::other)?; + + self.unlocked_inner + .server_processor + .enqueue_command(cmd, outbound_sender.clone()); + + Ok(()) + })); + + let mut unord = FuturesUnordered::new(); + unord.push(outbound_fut); + unord.push(inbound_fut); + + if let Some(Err(e)) = unord.next().await { + error!("{}", e); + } + + RunLoopEvent::Done + } } diff --git a/veilid-tools/src/virtual_network/router_server/server_processor.rs b/veilid-tools/src/virtual_network/router_server/server_processor.rs index 29b37ae1..54dcfe40 100644 --- a/veilid-tools/src/virtual_network/router_server/server_processor.rs +++ b/veilid-tools/src/virtual_network/router_server/server_processor.rs @@ -12,11 +12,9 @@ struct ServerProcessorInner { #[derive(Debug)] struct ServerProcessorUnlockedInner { - config: config::Config, + machine_registry: GlobalStateManager, receiver: flume::Receiver, sender: flume::Sender, - - machine_registry: MachineRegistry, } #[derive(Debug, Clone)] @@ -29,15 +27,14 @@ impl ServerProcessor { //////////////////////////////////////////////////////////////////////// // Public Interface - pub fn new(config: config::Config) -> Self { + pub fn new(machine_registry: GlobalStateManager) -> Self { let (sender, receiver) = flume::unbounded(); Self { unlocked_inner: Arc::new(ServerProcessorUnlockedInner { - config: config.clone(), sender, receiver, - machine_registry: MachineRegistry::new(config), + machine_registry, }), inner: Arc::new(Mutex::new(ServerProcessorInner {})), }