[skip ci] refactor and make multiple configs possible

This commit is contained in:
Christien Rioux 2025-01-07 20:30:41 -05:00
parent 9e7c41b635
commit d83f09d058
17 changed files with 664 additions and 582 deletions

View File

@ -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(

View File

@ -58,9 +58,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
false
}
pub fn can_allocate_v6(&self, prefix: u8) -> MachineRegistryResult<bool> {
pub fn can_allocate_v6(&self, prefix: u8) -> GlobalStateManagerResult<bool> {
if prefix > 128 {
return Err(MachineRegistryError::InvalidPrefix);
return Err(GlobalStateManagerError::InvalidPrefix(prefix));
}
let mut srng = StableRng::new(0);
@ -68,9 +68,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
Ok(opt_allocation.is_some())
}
pub fn can_allocate_v4(&self, prefix: u8) -> MachineRegistryResult<bool> {
pub fn can_allocate_v4(&self, prefix: u8) -> GlobalStateManagerResult<bool> {
if prefix > 32 {
return Err(MachineRegistryError::InvalidPrefix);
return Err(GlobalStateManagerError::InvalidPrefix(prefix));
}
let mut srng = StableRng::new(0);
@ -82,15 +82,15 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
&mut self,
allocation: Ipv4Net,
opt_tag: Option<T>,
) -> 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<T: fmt::Debug + Clone> AddressPool<T> {
&mut self,
allocation: Ipv6Net,
opt_tag: Option<T>,
) -> 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<T: fmt::Debug + Clone> AddressPool<T> {
srng: &mut StableRng,
prefix: u8,
tag: T,
) -> MachineRegistryResult<Option<Ipv4Net>> {
) -> GlobalStateManagerResult<Option<Ipv4Net>> {
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<T: fmt::Debug + Clone> AddressPool<T> {
srng: &mut StableRng,
prefix: u8,
tag: T,
) -> MachineRegistryResult<Option<Ipv6Net>> {
) -> GlobalStateManagerResult<Option<Ipv6Net>> {
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<T: fmt::Debug + Clone> AddressPool<T> {
pub fn release_allocation_v4(
&mut self,
allocation: Ipv4Net,
) -> MachineRegistryResult<Option<T>> {
) -> GlobalStateManagerResult<Option<T>> {
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<T: fmt::Debug + Clone> AddressPool<T> {
pub fn release_allocation_v6(
&mut self,
allocation: Ipv6Net,
) -> MachineRegistryResult<Option<T>> {
) -> GlobalStateManagerResult<Option<T>> {
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<T: fmt::Debug + Clone> AddressPool<T> {
pub fn clear_ipv4<F: FnMut(Ipv4Net, &T) -> bool>(
&mut self,
mut check: F,
) -> MachineRegistryResult<()> {
) -> GlobalStateManagerResult<()> {
if !self.is_ipv4() {
return Ok(());
}
@ -272,7 +272,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
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<T: fmt::Debug + Clone> AddressPool<T> {
pub fn clear_ipv6<F: FnMut(Ipv6Net, &T) -> bool>(
&mut self,
mut check: F,
) -> MachineRegistryResult<()> {
) -> GlobalStateManagerResult<()> {
if !self.is_ipv6() {
return Ok(());
}
@ -292,7 +294,9 @@ impl<T: fmt::Debug + Clone> AddressPool<T> {
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();

View File

@ -1,73 +1,86 @@
use super::*;
#[derive(Debug, Clone)]
pub(super) struct MachineRegistryInner {
unlocked_inner: Arc<MachineRegistryUnlockedInner>,
pub(super) struct GlobalStateManagerInner {
unlocked_inner: Arc<GlobalStateManagerUnlockedInner>,
srng: StableRng,
models: imbl::HashMap<String, config::Model>,
allocations: imbl::HashMap<String, config::Allocation>,
allocated_machines: imbl::HashSet<MachineStateId>,
profile_state_allocator: StateAllocator<ProfileState>,
machine_state_allocator: StateAllocator<MachineState>,
template_state_allocator: StateAllocator<TemplateState>,
network_state_allocator: StateAllocator<NetworkState>,
blueprint_state_allocator: StateAllocator<BlueprintState>,
profile_state_registry: StateRegistry<ProfileState>,
machine_state_registry: StateRegistry<MachineState>,
template_state_registry: StateRegistry<TemplateState>,
network_state_registry: StateRegistry<NetworkState>,
blueprint_state_registry: StateRegistry<BlueprintState>,
}
impl MachineRegistryInner {
impl GlobalStateManagerInner {
///////////////////////////////////////////////////////////
/// Public Interface
pub fn new(unlocked_inner: Arc<MachineRegistryUnlockedInner>) -> Self {
let srng = StableRng::new(unlocked_inner.config.seed.unwrap_or_default());
MachineRegistryInner {
pub fn new(unlocked_inner: Arc<GlobalStateManagerUnlockedInner>) -> 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<MachineId> {
// 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<MachineId> {
// 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::<MachineState>::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<ProfileState> {
&self.profile_state_allocator
}
pub(super) fn machine_states(&self) -> &StateAllocator<MachineState> {
&self.machine_state_allocator
}
pub(super) fn template_states(&self) -> &StateAllocator<TemplateState> {
&self.template_state_allocator
}
pub(super) fn network_states(&self) -> &StateAllocator<NetworkState> {
&self.network_state_allocator
}
pub(super) fn blueprint_states(&self) -> &StateAllocator<BlueprintState> {
&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<ProfileState> {
&mut self.profile_state_allocator
pub(super) fn models(&self) -> &imbl::HashMap<String, config::Model> {
&self.models
}
pub(super) fn machine_states_mut(&mut self) -> &mut StateAllocator<MachineState> {
&mut self.machine_state_allocator
pub(super) fn allocations(&self) -> &imbl::HashMap<String, config::Allocation> {
&self.allocations
}
pub(super) fn template_states_mut(&mut self) -> &mut StateAllocator<TemplateState> {
&mut self.template_state_allocator
pub(super) fn profile_states(&self) -> &StateRegistry<ProfileState> {
&self.profile_state_registry
}
pub(super) fn network_states_mut(&mut self) -> &mut StateAllocator<NetworkState> {
&mut self.network_state_allocator
pub(super) fn machine_states(&self) -> &StateRegistry<MachineState> {
&self.machine_state_registry
}
pub(super) fn blueprint_states_mut(&mut self) -> &mut StateAllocator<BlueprintState> {
&mut self.blueprint_state_allocator
pub(super) fn template_states(&self) -> &StateRegistry<TemplateState> {
&self.template_state_registry
}
pub(super) fn network_states(&self) -> &StateRegistry<NetworkState> {
&self.network_state_registry
}
pub(super) fn blueprint_states(&self) -> &StateRegistry<BlueprintState> {
&self.blueprint_state_registry
}
pub(super) fn profile_states_mut(&mut self) -> &mut StateRegistry<ProfileState> {
&mut self.profile_state_registry
}
pub(super) fn machine_states_mut(&mut self) -> &mut StateRegistry<MachineState> {
&mut self.machine_state_registry
}
pub(super) fn template_states_mut(&mut self) -> &mut StateRegistry<TemplateState> {
&mut self.template_state_registry
}
pub(super) fn network_states_mut(&mut self) -> &mut StateRegistry<NetworkState> {
&mut self.network_state_registry
}
pub(super) fn blueprint_states_mut(&mut self) -> &mut StateRegistry<BlueprintState> {
&mut self.blueprint_state_registry
}
// pub(super) fn get_or_create_machine_state(

View File

@ -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<T> = Result<T, GlobalStateManagerError>;
#[derive(Debug, Clone)]
pub struct GlobalStateManager {
unlocked_inner: Arc<GlobalStateManagerUnlockedInner>,
inner: Arc<Mutex<GlobalStateManagerInner>>,
}
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<MachineId> {
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)
}
}
}
}

View File

@ -69,7 +69,7 @@ pub struct BlueprintState {
pub type BlueprintStateId = StateId<BlueprintState>;
impl BlueprintState {
pub fn new(id: BlueprintStateId, name: String) -> MachineRegistryResult<BlueprintState> {
pub fn new(id: BlueprintStateId, name: String) -> GlobalStateManagerResult<BlueprintState> {
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<bool> {
) -> GlobalStateManagerResult<bool> {
// 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<bool> {
) -> GlobalStateManagerResult<bool> {
// 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<NetworkStateId> {
gsm_inner: &mut GlobalStateManagerInner,
) -> GlobalStateManagerResult<NetworkStateId> {
// 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<F, R>(&self, mut callback: F) -> MachineRegistryResult<Option<R>>
pub fn for_each_network_id<F, R>(&self, mut callback: F) -> GlobalStateManagerResult<Option<R>>
where
F: FnMut(NetworkStateId) -> MachineRegistryResult<Option<R>>,
F: FnMut(NetworkStateId) -> GlobalStateManagerResult<Option<R>>,
{
for network_id in &self.fields.networks {
if let Some(res) = callback(*network_id)? {

View File

@ -20,24 +20,19 @@ pub enum MachineLocationsList {
impl MachineLocationsList {
pub fn can_pick<F>(
&self,
machine_registry_inner: &mut MachineRegistryInner,
gsm_inner: &mut GlobalStateManagerInner,
mut network_filter: F,
) -> MachineRegistryResult<bool>
) -> GlobalStateManagerResult<bool>
where
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>,
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
{
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<F>(
&self,
machine_registry_inner: &mut MachineRegistryInner,
gsm_inner: &mut GlobalStateManagerInner,
mut network_filter: F,
) -> MachineRegistryResult<NetworkState>
) -> GlobalStateManagerResult<Option<NetworkState>>
where
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>,
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
{
// 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<F>(
&self,
machine_registry_inner: &MachineRegistryInner,
gsm_inner: &GlobalStateManagerInner,
network_state: NetworkState,
mut network_filter: F,
) -> MachineRegistryResult<bool>
) -> GlobalStateManagerResult<bool>
where
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>,
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
{
// 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<F>(
&self,
machine_registry_inner: &mut MachineRegistryInner,
gsm_inner: &mut GlobalStateManagerInner,
blueprint_state: BlueprintState,
mut network_filter: F,
) -> MachineRegistryResult<Option<BlueprintAvailability>>
) -> GlobalStateManagerResult<Option<BlueprintAvailability>>
where
F: FnMut(&MachineRegistryInner, NetworkStateId) -> MachineRegistryResult<bool>,
F: FnMut(&GlobalStateManagerInner, NetworkStateId) -> GlobalStateManagerResult<bool>,
{
// 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)));
}

View File

@ -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<String>,
opt_interface_flags: Option<InterfaceFlags>,
) -> MachineRegistryResult<Arc<String>> {
) -> GlobalStateManagerResult<Arc<String>> {
let interface_key = interface_name
.map(Arc::new)
.unwrap_or_else(|| self.next_free_interface_key());
if self.fields.interfaces.contains_key(&interface_key) {
return Err(MachineRegistryError::DuplicateName);
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<Ipv4Addr>,
opt_address_flags: Option<AddressFlags>,
) -> MachineRegistryResult<Ifv4Addr> {
) -> GlobalStateManagerResult<Ifv4Addr> {
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<Ipv6Addr>,
opt_address_flags: Option<AddressFlags>,
) -> MachineRegistryResult<Ifv6Addr> {
) -> GlobalStateManagerResult<Ifv6Addr> {
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<Vec<Arc<String>>> {
) -> GlobalStateManagerResult<Vec<Arc<String>>> {
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<String> = 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

View File

@ -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::*;

View File

@ -20,9 +20,9 @@ pub struct NetworkLocation<T> {
impl NetworkLocationsList {
pub fn pick_v4(
&self,
machine_registry_inner: &mut MachineRegistryInner,
gsm_inner: &mut GlobalStateManagerInner,
prefix: &WeightedList<u8>,
) -> MachineRegistryResult<NetworkLocation<Ipv4Net>> {
) -> GlobalStateManagerResult<Option<NetworkLocation<Ipv4Net>>> {
// 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<u8>,
) -> MachineRegistryResult<NetworkLocation<Ipv6Net>> {
) -> GlobalStateManagerResult<Option<NetworkLocation<Ipv6Net>>> {
// 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),
})
}))
}
}
}

View File

@ -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<NetworkStateIpv4GatewayParams>,
) -> 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<NetworkStateIpv6GatewayParams>,
) -> 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<bool> {
pub fn is_active(&self) -> GlobalStateManagerResult<bool> {
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<Ipv4Addr>,
) -> MachineRegistryResult<Ifv4Addr> {
let net = self.allocate_subnet_v4(machine_registry_inner, owner_tag, opt_address, 32)?;
) -> GlobalStateManagerResult<Ifv4Addr> {
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<Ipv4Addr>,
prefix: u8,
) -> MachineRegistryResult<Ipv4Net> {
) -> GlobalStateManagerResult<Ipv4Net> {
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<Option<OwnerTag>> {
) -> GlobalStateManagerResult<Option<OwnerTag>> {
self.release_subnet_v4(Ipv4Net::new(addr, 32).expect("must succeed"))
}
pub fn release_subnet_v4(&mut self, net: Ipv4Net) -> MachineRegistryResult<Option<OwnerTag>> {
pub fn release_subnet_v4(
&mut self,
net: Ipv4Net,
) -> GlobalStateManagerResult<Option<OwnerTag>> {
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<Ipv6Addr>,
) -> MachineRegistryResult<Ifv6Addr> {
let net = self.allocate_subnet_v6(machine_registry_inner, owner_tag, opt_address, 128)?;
) -> GlobalStateManagerResult<Ifv6Addr> {
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<Ipv6Addr>,
prefix: u8,
) -> MachineRegistryResult<Ipv6Net> {
) -> GlobalStateManagerResult<Ipv6Net> {
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<Option<OwnerTag>> {
) -> GlobalStateManagerResult<Option<OwnerTag>> {
self.release_subnet_v6(Ipv6Net::new(addr, 128).expect("must succeed"))
}
pub fn release_subnet_v6(&mut self, net: Ipv6Net) -> MachineRegistryResult<Option<OwnerTag>> {
pub fn release_subnet_v6(
&mut self,
net: Ipv6Net,
) -> GlobalStateManagerResult<Option<OwnerTag>> {
let mut address_pool = self.fields.address_pool.clone();
let opt_tag = address_pool.release_allocation_v6(net)?;

View File

@ -4,6 +4,10 @@ use std::marker::PhantomData;
pub trait State: fmt::Debug + Clone {
fn id(&self) -> StateId<Self>;
fn name(&self) -> Option<String>;
fn debug_name(&self) -> String {
self.name()
.unwrap_or_else(|| format!("<{}>", self.id().external_id()))
}
}
type StateIdInternal = u64;
@ -44,14 +48,14 @@ impl<S: State> core::hash::Hash for StateId<S> {
}
#[derive(Debug, Clone)]
pub struct StateAllocator<S: State> {
pub struct StateRegistry<S: State> {
state_id_by_name: imbl::HashMap<Arc<String>, StateIdInternal>,
state_by_id: imbl::HashMap<StateIdInternal, Option<S>>,
next_state_id: StateIdInternal,
free_state_ids: imbl::Vector<StateIdInternal>,
}
impl<S: State> StateAllocator<S> {
impl<S: State> StateRegistry<S> {
pub fn new() -> Self {
Self {
state_id_by_name: imbl::HashMap::new(),
@ -90,10 +94,10 @@ impl<S: State> StateAllocator<S> {
StateId(state_id, PhantomData {})
}
pub fn release_id(&mut self, id: StateId<S>) -> MachineRegistryResult<()> {
pub fn release_id(&mut self, id: StateId<S>) -> 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<S: State> StateAllocator<S> {
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<S: State> StateAllocator<S> {
Ok(())
}
pub fn detach_state(&mut self, id: StateId<S>) -> MachineRegistryResult<S> {
pub fn detach_state(&mut self, id: StateId<S>) -> GlobalStateManagerResult<S> {
// 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<S: State> StateAllocator<S> {
Ok(state)
}
pub fn get_state(&self, id: StateId<S>) -> MachineRegistryResult<S> {
pub fn get_state(&self, id: StateId<S>) -> GlobalStateManagerResult<S> {
// 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<S: State> StateAllocator<S> {
}
}
impl<S: State> Default for StateAllocator<S> {
impl<S: State> Default for StateRegistry<S> {
fn default() -> Self {
Self::new()
}

View File

@ -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<bool> {
fn network_filter(&self, network_state_id: NetworkStateId) -> GlobalStateManagerResult<bool> {
// 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<MachineStateId> {
gsm_inner: &mut GlobalStateManagerInner,
) -> GlobalStateManagerResult<MachineStateId> {
// 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(),

View File

@ -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<T> = Result<T, MachineRegistryError>;
#[derive(Debug, Clone)]
pub struct MachineRegistry {
inner: Arc<Mutex<MachineRegistryInner>>,
unlocked_inner: Arc<MachineRegistryUnlockedInner>,
}
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<MachineId> {
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)
}
}
}
}

View File

@ -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<T> = Result<T, RouterServerError>;
@ -40,10 +42,10 @@ enum RunLoopEvent {
#[derive(Debug)]
struct RouterServerUnlockedInner {
config: config::Config,
new_client_sender: flume::Sender<SendPinBoxFuture<RunLoopEvent>>,
new_client_receiver: flume::Receiver<SendPinBoxFuture<RunLoopEvent>>,
server_processor: ServerProcessor,
global_state_manager: GlobalStateManager,
}
#[derive(Debug)]
@ -60,69 +62,44 @@ pub struct RouterServer {
inner: Arc<Mutex<RouterServerInner>>,
}
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<R, W>(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::<ServerProcessorCommand>(&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<R, W>(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::<ServerProcessorCommand>(&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
}
}

View File

@ -12,11 +12,9 @@ struct ServerProcessorInner {
#[derive(Debug)]
struct ServerProcessorUnlockedInner {
config: config::Config,
machine_registry: GlobalStateManager,
receiver: flume::Receiver<ServerProcessorCommandRecord>,
sender: flume::Sender<ServerProcessorCommandRecord>,
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 {})),
}