From a16a54de0c2029f49ae9e37d94a806d9d4e65dba Mon Sep 17 00:00:00 2001 From: Christien Rioux Date: Thu, 16 Jan 2025 11:06:40 -0500 Subject: [PATCH] [skip ci] tracing options --- Cargo.lock | 1 + veilid-tools/Cargo.toml | 12 + veilid-tools/src/bin/virtual_router/main.rs | 84 +++++- .../virtual_network/router_server/config.rs | 4 - .../global_state_manager_inner.rs | 152 ++++++++++- .../state/blueprint_state.rs | 6 +- .../state/machine_locations_list.rs | 181 ------------- .../state/machine_state.rs | 38 +-- .../global_state_manager/state/mod.rs | 8 +- .../state/network_locations_list.rs | 243 ------------------ .../state/network_state.rs | 2 +- .../state/template_state.rs | 8 +- 12 files changed, 260 insertions(+), 479 deletions(-) delete mode 100644 veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_locations_list.rs delete mode 100644 veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_locations_list.rs diff --git a/Cargo.lock b/Cargo.lock index bee15dea..93694114 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6660,6 +6660,7 @@ dependencies = [ "static_assertions", "stop-token", "thiserror 1.0.69", + "time", "tokio", "tokio-stream", "tokio-util", diff --git a/veilid-tools/Cargo.toml b/veilid-tools/Cargo.toml index 8c7bf0d9..7b3c3451 100644 --- a/veilid-tools/Cargo.toml +++ b/veilid-tools/Cargo.toml @@ -16,6 +16,11 @@ resolver = "2" crate-type = ["cdylib", "staticlib", "rlib"] path = "src/lib.rs" +[[bin]] +name = "virtual_router" +path = "src/bin/virtual_router/main.rs" +required-features = ["virtual-router"] + [features] default = ["rt-tokio", "virtual-network", "virtual-network-server"] rt-async-std = [ @@ -54,6 +59,7 @@ virtual-network-server = [ "dep:ws_stream_tungstenite", "dep:rand_chacha", ] +virtual-router = ["tracing", "virtual-network-server", "dep:time"] [dependencies] tracing = { version = "0.1.40", features = [ @@ -62,6 +68,7 @@ tracing = { version = "0.1.40", features = [ ], optional = true } tracing-subscriber = { version = "0.3.18", features = [ "env-filter", + "time", ], optional = true } log = { version = "0.4.22" } eyre = "0.6.12" @@ -86,11 +93,16 @@ range-set-blaze = "0.1.16" flume = { version = "0.11.0", features = ["async"] } imbl = { version = "3.0.0", features = ["serde"] } + # Dependencies for native builds only # Linux, Windows, Mac, iOS, Android [target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies] async-io = { version = "1.13.0" } async-std = { version = "1.12.0", features = ["unstable"], optional = true } +time = { version = "0.3.36", features = [ + "local-offset", + "formatting", +], optional = true } chrono = "0.4.38" ctrlc = "^3" futures-util = { version = "0.3.30", default-features = false, features = [ diff --git a/veilid-tools/src/bin/virtual_router/main.rs b/veilid-tools/src/bin/virtual_router/main.rs index 36f29dc7..ef38ed24 100644 --- a/veilid-tools/src/bin/virtual_router/main.rs +++ b/veilid-tools/src/bin/virtual_router/main.rs @@ -1,10 +1,11 @@ #![cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] use cfg_if::*; -use clap::Parser; +use clap::{Args, Parser}; use parking_lot::*; use std::path::PathBuf; use stop_token::StopSource; +use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, Layer, Registry}; use veilid_tools::*; use virtual_network::*; @@ -26,6 +27,25 @@ cfg_if! { } } +const DEFAULT_IGNORE_LOG_TARGETS: &[&str] = &["tokio"]; + +#[derive(Args, Debug, Clone)] +#[group(multiple = false)] +pub struct Logging { + /// Turn on debug logging on the terminal + #[arg(long, group = "logging")] + debug: bool, + /// Turn on trace logging on the terminal + #[arg(long, group = "logging")] + trace: bool, + /// Ignore log targets + #[arg(long)] + ignore_log_targets: Vec, + /// Enable log targets + #[arg(long)] + enable_log_targets: Vec, +} + #[derive(Parser, Debug)] #[command(author, version, about = "Veilid VirtualRouter")] struct CmdlineArgs { @@ -50,6 +70,66 @@ struct CmdlineArgs { /// Instead of running the virtual router, print the configuration it would use to the console #[arg(long)] dump_config: bool, + + #[command(flatten)] + logging: Logging, +} + +fn setup_tracing(logging: &Logging) -> Result<(), String> { + // Set up subscriber and layers + let subscriber = Registry::default(); + let mut layers = Vec::new(); + + // Get log level + let level = if logging.trace { + tracing::Level::TRACE + } else if logging.debug { + tracing::Level::DEBUG + } else { + tracing::Level::INFO + }; + + // Get ignore log targets + let mut ignore_log_targets: Vec = DEFAULT_IGNORE_LOG_TARGETS + .iter() + .map(|x| x.to_string()) + .collect(); + for x in &logging.ignore_log_targets { + if !ignore_log_targets.contains(x) { + ignore_log_targets.push(x.clone()); + } + } + ignore_log_targets.retain(|x| !logging.enable_log_targets.contains(x)); + + let timer = + time::format_description::parse("[hour]:[minute]:[second]").expect("invalid time format"); + + // Use chrono instead of time crate to get local offset + let offset_in_sec = chrono::Local::now().offset().local_minus_utc(); + let time_offset = + time::UtcOffset::from_whole_seconds(offset_in_sec).expect("invalid utc offset"); + let timer = fmt::time::OffsetTime::new(time_offset, timer); + + let mut filter = tracing_subscriber::EnvFilter::from_default_env().add_directive(level.into()); + for x in ignore_log_targets { + filter = filter.add_directive(format!("{x}=off").parse().unwrap()); + } + + let layer = fmt::Layer::new() + .compact() + .with_timer(timer) + .with_ansi(true) + .with_writer(std::io::stdout) + .with_filter(filter); + + layers.push(layer.boxed()); + + let subscriber = subscriber.with(layers); + subscriber + .try_init() + .map_err(|e| format!("failed to initialize tracing: {e}"))?; + + Ok(()) } fn main() -> Result<(), String> { @@ -68,6 +148,8 @@ fn main() -> Result<(), String> { let args = CmdlineArgs::parse(); + setup_tracing(&args.logging)?; + let initial_config = config::Config::new(&args.config_file, args.no_predefined_config) .map_err(|e| format!("Error loading config: {}", e))?; diff --git a/veilid-tools/src/virtual_network/router_server/config.rs b/veilid-tools/src/virtual_network/router_server/config.rs index 13cb2f87..aad6c210 100644 --- a/veilid-tools/src/virtual_network/router_server/config.rs +++ b/veilid-tools/src/virtual_network/router_server/config.rs @@ -61,9 +61,6 @@ pub enum MachineLocation { #[serde(default)] address6: Option, }, - Blueprint { - blueprint: String, - }, } impl Validate for MachineLocation { @@ -83,7 +80,6 @@ impl Validate for MachineLocation { ); } } - MachineLocation::Blueprint { blueprint: _ } => {} } if !errors.is_empty() { diff --git a/veilid-tools/src/virtual_network/router_server/global_state_manager/global_state_manager_inner.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/global_state_manager_inner.rs index d52951bb..97f11903 100644 --- a/veilid-tools/src/virtual_network/router_server/global_state_manager/global_state_manager_inner.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/global_state_manager_inner.rs @@ -136,8 +136,14 @@ impl GlobalStateManagerInner { } // Create all template states + for (name, template) in cfg.templates { + self.execute_config_template(name, template)?; + } // Create all machine states + for (name, machine) in cfg.machines { + self.execute_config_machine(name, machine)?; + } Ok(()) } @@ -647,7 +653,7 @@ impl GlobalStateManagerInner { let locations = match ipv4.location.clone() { config::BlueprintLocation::Allocation { allocation } => { - NetworkLocationsList::Allocations { + BlueprintLocationsList::Allocations { allocations: allocation, } } @@ -658,7 +664,7 @@ impl GlobalStateManagerInner { .get_state_id_by_name(n) .ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone())) })?; - NetworkLocationsList::Networks { networks } + BlueprintLocationsList::Networks { networks } } else { let default_network = self.or_default_network(None)?; let default_network_state_id = self @@ -666,7 +672,7 @@ impl GlobalStateManagerInner { .get_state_id_by_name(&default_network) .ok_or(GlobalStateManagerError::NetworkNotFound(default_network))?; - NetworkLocationsList::Networks { + BlueprintLocationsList::Networks { networks: WeightedList::Single(default_network_state_id), } } @@ -714,7 +720,7 @@ impl GlobalStateManagerInner { .get_state_id_by_name(n) .ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone())) })?; - Some(MachineLocationsList::Networks { networks }) + Some(TemplateLocationsList::Networks { networks }) } Some(config::TemplateLocation::Blueprint { blueprint }) => { let blueprints = blueprint.try_map(|n| { @@ -722,7 +728,7 @@ impl GlobalStateManagerInner { .get_state_id_by_name(n) .ok_or_else(|| GlobalStateManagerError::BlueprintNotFound(n.clone())) })?; - Some(MachineLocationsList::Blueprints { blueprints }) + Some(TemplateLocationsList::Blueprints { blueprints }) } None => None, }; @@ -757,7 +763,7 @@ impl GlobalStateManagerInner { let locations = match ipv6.location.clone() { config::BlueprintLocation::Allocation { allocation } => { - NetworkLocationsList::Allocations { + BlueprintLocationsList::Allocations { allocations: allocation, } } @@ -768,7 +774,7 @@ impl GlobalStateManagerInner { .get_state_id_by_name(n) .ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone())) })?; - NetworkLocationsList::Networks { networks } + BlueprintLocationsList::Networks { networks } } else { let default_network = self.or_default_network(None)?; let default_network_state_id = self @@ -776,7 +782,7 @@ impl GlobalStateManagerInner { .get_state_id_by_name(&default_network) .ok_or(GlobalStateManagerError::NetworkNotFound(default_network))?; - NetworkLocationsList::Networks { + BlueprintLocationsList::Networks { networks: WeightedList::Single(default_network_state_id), } } @@ -824,7 +830,7 @@ impl GlobalStateManagerInner { .get_state_id_by_name(n) .ok_or_else(|| GlobalStateManagerError::NetworkNotFound(n.clone())) })?; - Some(MachineLocationsList::Networks { networks }) + Some(TemplateLocationsList::Networks { networks }) } Some(config::TemplateLocation::Blueprint { blueprint }) => { let blueprints = blueprint.try_map(|n| { @@ -832,7 +838,7 @@ impl GlobalStateManagerInner { .get_state_id_by_name(n) .ok_or_else(|| GlobalStateManagerError::BlueprintNotFound(n.clone())) })?; - Some(MachineLocationsList::Blueprints { blueprints }) + Some(TemplateLocationsList::Blueprints { blueprints }) } None => None, }; @@ -851,6 +857,132 @@ impl GlobalStateManagerInner { Ok(()) } + fn execute_config_template( + &mut self, + name: String, + template: config::Template, + ) -> GlobalStateManagerResult<()> { + if self + .template_state_registry + .get_state_id_by_name(&name) + .is_some() + { + return Err(GlobalStateManagerError::DuplicateName(name)); + } + + let id = self.template_state_registry.allocate_id(); + let state = { + let mut template_state = TemplateState::new(id, name); + + template_state.set_disable_capabilities(template.disable_capabilities); + if let Some(wl) = template.limits.machine_count { + template_state.set_limit_machine_count(Some(self.srng().weighted_choice(wl))); + } + template_state + .set_limit_machines_per_network(template.limits.machines_per_network.clone()); + + match template.location.clone() { + config::TemplateLocation::Network { network } => { + let networks = network.try_map(|x| { + self.network_state_registry + .get_state_id_by_name(x) + .ok_or_else(|| GlobalStateManagerError::NetworkNotFound(x.clone())) + })?; + + template_state.set_networks_list(networks); + } + config::TemplateLocation::Blueprint { blueprint } => { + let blueprints = blueprint.try_map(|x| { + self.blueprint_state_registry + .get_state_id_by_name(x) + .ok_or_else(|| GlobalStateManagerError::BlueprintNotFound(x.clone())) + })?; + + template_state.set_blueprints_list(blueprints); + } + } + + Ok(template_state) + } + .inspect_err(|_| { + self.template_state_registry + .release_id(id) + .expect("must release"); + })?; + self.template_state_registry + .attach_state(state) + .expect("must attach"); + Ok(()) + } + + fn execute_config_machine( + &mut self, + name: String, + machine: config::Machine, + ) -> GlobalStateManagerResult<()> { + if self + .machine_state_registry + .get_state_id_by_name(&name) + .is_some() + { + return Err(GlobalStateManagerError::DuplicateName(name)); + } + + let id = self.machine_state_registry.allocate_id(); + let state = { + let mut machine_state = MachineState::new(id, Some(name), MachineOrigin::Config); + + machine_state.set_disable_capabilities(machine.disable_capabilities); + machine_state.set_bootstrap(machine.bootstrap); + + // Create primary interface + let interface_name = machine_state.allocate_interface(None, None)?; + + match machine.location { + config::MachineLocation::Network { + network, + address4, + address6, + } => { + // Look up network + let network_state_id = self + .network_state_registry + .get_state_id_by_name(&network) + .ok_or(GlobalStateManagerError::NetworkNotFound(network))?; + + machine_state.attach_network(self, &interface_name, network_state_id)?; + if let Some(address4) = address4 { + machine_state.allocate_address_ipv4( + self, + &interface_name, + Some(address4), + None, + )?; + } + if let Some(address6) = address6 { + machine_state.allocate_address_ipv6( + self, + &interface_name, + Some(address6), + None, + )?; + } + } + } + + Ok(machine_state) + } + .inspect_err(|_| { + self.machine_state_registry + .release_id(id) + .expect("must release"); + })?; + self.machine_state_registry + .attach_state(state) + .expect("must attach"); + Ok(()) + } + fn resolve_address_pool( &self, allocation_name: String, diff --git a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/blueprint_state.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/blueprint_state.rs index 1a6daf53..b76217f9 100644 --- a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/blueprint_state.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/blueprint_state.rs @@ -10,14 +10,14 @@ struct BlueprintStateImmutable { #[derive(Debug, Clone)] pub struct BlueprintStateIpv4Params { - pub locations: NetworkLocationsList, + pub locations: BlueprintLocationsList, pub prefix: WeightedList, pub gateway: Option, } #[derive(Debug, Clone)] pub struct BlueprintStateIpv6Params { - pub locations: NetworkLocationsList, + pub locations: BlueprintLocationsList, pub prefix: WeightedList, pub gateway: Option, } @@ -26,7 +26,7 @@ pub struct BlueprintStateIpv6Params { pub struct BlueprintStateGatewayParams { pub translation: WeightedList, pub upnp: Probability, - pub locations: Option, + pub locations: Option, } #[derive(Debug, Clone)] diff --git a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_locations_list.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_locations_list.rs deleted file mode 100644 index d2d5025c..00000000 --- a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_locations_list.rs +++ /dev/null @@ -1,181 +0,0 @@ -use super::*; - -#[derive(Debug, Clone)] -enum BlueprintAvailability { - Existing(NetworkState), - Generate(BlueprintState), -} - -/// Locations where a machine can be instantiated -#[derive(Debug, Clone)] -pub enum MachineLocationsList { - Networks { - networks: WeightedList, - }, - Blueprints { - blueprints: WeightedList, - }, -} - -impl MachineLocationsList { - pub fn can_pick( - &self, - gsm_inner: &mut GlobalStateManagerInner, - mut network_filter: F, - ) -> GlobalStateManagerResult - where - 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 = gsm_inner.network_states().get_state(*id)?; - self.is_network_available(gsm_inner, network_state, &mut network_filter) - })? - .is_none() - { - return Ok(false); - }; - } - MachineLocationsList::Blueprints { blueprints } => { - // 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 = gsm_inner.blueprint_states().get_state(*id)?; - - self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter) - .map(|x| x.is_some()) - })? - .is_none() - { - return Ok(false); - }; - } - }; - Ok(true) - } - - pub fn pick( - &self, - gsm_inner: &mut GlobalStateManagerInner, - mut network_filter: F, - ) -> GlobalStateManagerResult> - where - 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 = gsm_inner.network_states().get_state(*id)?; - if self.is_network_available( - gsm_inner, - network_state.clone(), - &mut network_filter, - )? { - Ok(Some(network_state)) - } else { - Ok(None) - } - })? - else { - return Ok(None); - }; - - // Weighted choice of network now that we have a candidate list - let network_state = gsm_inner.srng().weighted_choice(available_networks); - - // Return network state to use - network_state - } - 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 = gsm_inner.blueprint_states().get_state(*id)?; - - self.is_blueprint_available(gsm_inner, blueprint_state, &mut network_filter) - })? - else { - return Ok(None); - }; - - // Weighted choice of blueprint now that we have a candidate list - 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(gsm_inner)?; - - // Update blueprint state - gsm_inner.blueprint_states_mut().set_state(blueprint_state); - - // Return network state - gsm_inner.network_states().get_state(network_state_id)? - } - } - } - }; - - Ok(Some(network_state)) - } - - fn is_network_available( - &self, - gsm_inner: &GlobalStateManagerInner, - network_state: NetworkState, - mut network_filter: F, - ) -> GlobalStateManagerResult - where - F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult, - { - // If the network is not active, it is not available - if !network_state.is_active()? { - return Ok(false); - } - - // Check the network filter - if !network_filter(gsm_inner, network_state.id())? { - return Ok(false); - } - - Ok(true) - } - - fn is_blueprint_available( - &self, - gsm_inner: &mut GlobalStateManagerInner, - blueprint_state: BlueprintState, - mut network_filter: F, - ) -> GlobalStateManagerResult> - where - 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 = 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)); - } - // Try next network - Ok(None) - })? { - // We found a usable network - return Ok(Some(BlueprintAvailability::Existing( - available_network_state, - ))); - } - - // If the blueprint is active, it is available because it can make a new network - if blueprint_state.is_active(gsm_inner) { - return Ok(Some(BlueprintAvailability::Generate(blueprint_state))); - } - - Ok(None) - } -} diff --git a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_state.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_state.rs index 5ca4962b..394eaaa2 100644 --- a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_state.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/machine_state.rs @@ -2,7 +2,7 @@ use super::*; #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum MachineOrigin { - InitialConfig, + Config, Direct, Template(TemplateStateId), } @@ -70,9 +70,7 @@ impl MachineState { .get_state(generating_template) .expect("must exist"); template_state.on_machine_released(self.id()); - gsm_inner - .template_states_mut() - .set_state(template_state); + gsm_inner.template_states_mut().set_state(template_state); } } @@ -167,9 +165,7 @@ impl MachineState { (*interface_key).clone(), )); }; - let mut network_state = gsm_inner - .network_states() - .get_state(network_id)?; + let mut network_state = gsm_inner.network_states().get_state(network_id)?; // Allocate interface address let is_dynamic = opt_address.is_none(); @@ -180,9 +176,7 @@ impl MachineState { )?; // Update the network state - gsm_inner - .network_states_mut() - .set_state(network_state); + gsm_inner.network_states_mut().set_state(network_state); // Get address flags let flags = opt_address_flags.unwrap_or(AddressFlags { @@ -237,9 +231,7 @@ impl MachineState { (*interface_key).clone(), )); }; - let mut network_state = gsm_inner - .network_states() - .get_state(network_id)?; + let mut network_state = gsm_inner.network_states().get_state(network_id)?; // Allocate interface address let is_dynamic = opt_address.is_none(); @@ -249,9 +241,7 @@ impl MachineState { opt_address, )?; // Update the network state - gsm_inner - .network_states_mut() - .set_state(network_state); + gsm_inner.network_states_mut().set_state(network_state); // Get address flags let flags = opt_address_flags.unwrap_or(AddressFlags { @@ -384,9 +374,7 @@ impl MachineState { }; // Get the network state - let mut network_state = gsm_inner - .network_states() - .get_state(network_id)?; + let mut network_state = gsm_inner.network_states().get_state(network_id)?; // Release the address from the network match address { @@ -395,9 +383,7 @@ impl MachineState { }; // Update the network state - gsm_inner - .network_states_mut() - .set_state(network_state); + gsm_inner.network_states_mut().set_state(network_state); // Remove the address from the interface let addrs: Vec<_> = machine_state_interface @@ -479,9 +465,7 @@ impl MachineState { }; // Get the network state - let mut network_state = gsm_inner - .network_states() - .get_state(network_id)?; + let mut network_state = gsm_inner.network_states().get_state(network_id)?; // Release the addresses from the network for addr in &machine_state_interface.network_interface.addrs { @@ -492,9 +476,7 @@ impl MachineState { } // Update the network state - gsm_inner - .network_states_mut() - .set_state(network_state); + gsm_inner.network_states_mut().set_state(network_state); // Remove the addresses from the interface let mut new_intf = (*machine_state_interface.network_interface).clone(); diff --git a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/mod.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/mod.rs index 267f5f23..e67aecb1 100644 --- a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/mod.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/mod.rs @@ -1,19 +1,19 @@ +mod blueprint_locations_list; mod blueprint_state; -mod machine_locations_list; mod machine_state; -mod network_locations_list; mod network_state; mod profile_state; mod state_registry; +mod template_locations_list; mod template_state; use super::*; +pub use blueprint_locations_list::*; pub use blueprint_state::*; -pub use machine_locations_list::*; pub use machine_state::*; -pub use network_locations_list::*; pub use network_state::*; pub use profile_state::*; pub use state_registry::*; +pub use template_locations_list::*; pub use template_state::*; diff --git a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_locations_list.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_locations_list.rs deleted file mode 100644 index 5477d45f..00000000 --- a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_locations_list.rs +++ /dev/null @@ -1,243 +0,0 @@ -use super::*; - -/// Locations where a network can be instantiated -#[derive(Debug, Clone)] -pub enum NetworkLocationsList { - /// Network will be a new allocation - Allocations { allocations: WeightedList }, - /// Network will be allocated as a subnet of an existing network - Networks { - networks: WeightedList, - }, -} - -#[derive(Debug, Clone)] -pub struct NetworkLocation { - pub scope: Vec, - pub reserve: Vec, - pub super_net: Option, -} - -impl NetworkLocationsList { - pub fn pick_v4( - &self, - gsm_inner: &mut GlobalStateManagerInner, - prefix: &WeightedList, - ) -> GlobalStateManagerResult>> { - // Get maximum prefix - let max_prefix = prefix - .iter() - .max() - .copied() - .expect("must have at least one element"); - - // Get addresses for network - match self { - NetworkLocationsList::Allocations { allocations } => { - // Get allocations which have subnets that would fit - // our maximum requested prefix - let Some(address_pools) = allocations.try_filter_map(|allocation_name| { - let allocation = gsm_inner - .allocations() - .get(allocation_name) - .expect("must exist"); - if allocation.address_pool.can_allocate_v4(max_prefix)? { - Ok(Some(allocation.address_pool.clone())) - } else { - Ok(None) - } - })? - else { - return Ok(None); - }; - - // Pick an address pool - let mut address_pool = gsm_inner.srng().weighted_choice(address_pools); - - // Pick a prefix length that would fit in the subnet - let opt_subnet = prefix - .try_filter(|p| address_pool.can_allocate_v4(*p))? - .as_ref() - .map(|wl| { - let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl); - - address_pool.allocate_random_v4(gsm_inner.srng(), subnet_prefix, ()) - }) - .transpose()? - .flatten(); - let Some(subnet) = opt_subnet else { - return Ok(None); - }; - Ok(Some(NetworkLocation { - scope: vec![subnet], - reserve: Vec::new(), - 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 = gsm_inner - .network_states() - .get_state(*network_id) - .expect("must exist"); - - Ok(super_network_state.can_allocate_subnet_v4(None, max_prefix)) - })? - else { - return Ok(None); - }; - - // Pick a network - 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"); - - // Pick a prefix that fits in this network and allocate from it - let opt_subnet = prefix - .filter(|p| super_network_state.can_allocate_subnet_v4(None, *p)) - .as_ref() - .map(|wl| { - let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl); - - // Allocate subnet from this network - super_network_state.allocate_subnet_v4( - gsm_inner, - OwnerTag::Network(super_network_state.id()), - None, - subnet_prefix, - ) - }) - .transpose()?; - let Some(subnet) = opt_subnet else { - return Ok(None); - }; - - // Update network state - gsm_inner - .network_states_mut() - .set_state(super_network_state); - - Ok(Some(NetworkLocation { - scope: vec![subnet], - reserve: Vec::new(), - super_net: Some(super_network_id), - })) - } - } - } - - pub fn pick_v6( - &self, - gsm_inner: &mut GlobalStateManagerInner, - prefix: &WeightedList, - ) -> GlobalStateManagerResult>> { - // Get maximum prefix - let max_prefix = prefix - .iter() - .max() - .copied() - .expect("must have at least one element"); - - // Get addresses for network - match self { - NetworkLocationsList::Allocations { allocations } => { - // Get allocations which have subnets that would fit - // our maximum requested prefix - let Some(address_pools) = allocations.try_filter_map(|allocation_name| { - let allocation = gsm_inner - .allocations() - .get(allocation_name) - .expect("must exist"); - if allocation.address_pool.can_allocate_v6(max_prefix)? { - Ok(Some(allocation.address_pool.clone())) - } else { - Ok(None) - } - })? - else { - return Ok(None); - }; - - // Pick an address pool - let mut address_pool = gsm_inner.srng().weighted_choice(address_pools); - - // Pick a prefix length that would fit in the subnet - let opt_subnet = prefix - .try_filter(|p| address_pool.can_allocate_v6(*p))? - .as_ref() - .map(|wl| { - let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl); - - address_pool.allocate_random_v6(gsm_inner.srng(), subnet_prefix, ()) - }) - .transpose()? - .flatten(); - let Some(subnet) = opt_subnet else { - return Ok(None); - }; - Ok(Some(NetworkLocation { - scope: vec![subnet], - reserve: Vec::new(), - 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 = gsm_inner - .network_states() - .get_state(*network_id) - .expect("must exist"); - - Ok(super_network_state.can_allocate_subnet_v6(None, max_prefix)) - })? - else { - return Ok(None); - }; - - // Pick a network - 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"); - - // Pick a prefix that fits in this network and allocate from it - let opt_subnet = prefix - .filter(|p| super_network_state.can_allocate_subnet_v6(None, *p)) - .as_ref() - .map(|wl| { - let subnet_prefix = *gsm_inner.srng().weighted_choice_ref(wl); - - // Allocate subnet from this network - super_network_state.allocate_subnet_v6( - gsm_inner, - OwnerTag::Network(super_network_state.id()), - None, - subnet_prefix, - ) - }) - .transpose()?; - let Some(subnet) = opt_subnet else { - return Ok(None); - }; - - // Update network state - gsm_inner - .network_states_mut() - .set_state(super_network_state); - - Ok(Some(NetworkLocation { - scope: vec![subnet], - reserve: Vec::new(), - super_net: Some(super_network_id), - })) - } - } - } -} diff --git a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_state.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_state.rs index c36e87df..57421fb4 100644 --- a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_state.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/network_state.rs @@ -9,7 +9,7 @@ pub enum OwnerTag { #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum NetworkOrigin { - InitialConfig, + Config, Direct, Blueprint(BlueprintStateId), } diff --git a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/template_state.rs b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/template_state.rs index 2d4b6c4a..0f49d19e 100644 --- a/veilid-tools/src/virtual_network/router_server/global_state_manager/state/template_state.rs +++ b/veilid-tools/src/virtual_network/router_server/global_state_manager/state/template_state.rs @@ -18,7 +18,7 @@ struct PerNetworkInfo { struct TemplateStateFields { limit_machine_count: Option, limit_machines_per_network: Option>, - locations_list: Option, + locations_list: Option, machines: imbl::HashSet, machines_per_network: imbl::HashMap, disable_capabilities: imbl::Vector>, @@ -58,7 +58,7 @@ impl TemplateState { } pub fn set_networks_list(&mut self, networks: WeightedList) { - let locations_list = Some(MachineLocationsList::Networks { networks }); + let locations_list = Some(TemplateLocationsList::Networks { networks }); // Update fields self.fields = Arc::new(TemplateStateFields { @@ -67,8 +67,8 @@ impl TemplateState { }); } - pub fn set_blueprints_list(mut self, blueprints: WeightedList) { - let locations_list = Some(MachineLocationsList::Blueprints { blueprints }); + pub fn set_blueprints_list(&mut self, blueprints: WeightedList) { + let locations_list = Some(TemplateLocationsList::Blueprints { blueprints }); // Update fields self.fields = Arc::new(TemplateStateFields {