mirror of
https://gitlab.com/veilid/veilid.git
synced 2025-01-11 23:39:36 -05:00
[skip ci] checkpoint
This commit is contained in:
parent
c361dce995
commit
10534b5bb7
@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
|
||||
/// Locations where a machine can be instantiated
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MachineLocationsList {
|
||||
Networks {
|
||||
networks: WeightedList<NetworkStateId>,
|
||||
|
@ -156,25 +156,26 @@ impl NetworkState {
|
||||
}
|
||||
|
||||
pub fn clear_ipv4(
|
||||
&self,
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
) -> MachineRegistryResult<()> {
|
||||
let Some(ipv4) = inner.ipv4.as_mut() else {
|
||||
let Some(ipv4) = self.fields.ipv4.clone() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
inner.address_pool.clear_ipv4(|_n, t| match t {
|
||||
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,
|
||||
OwnerTag::Network(nsid) => *nsid != self.id(),
|
||||
OwnerTag::Gateway(nsid) => *nsid != self.id(),
|
||||
})?;
|
||||
|
||||
// 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 {
|
||||
if gateway.params.external_network != self.id() {
|
||||
// Get the external network state
|
||||
let external_network_state = machine_registry_inner
|
||||
let mut external_network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(gateway.params.external_network)
|
||||
.expect("must succeed");
|
||||
@ -183,35 +184,47 @@ impl NetworkState {
|
||||
external_network_state
|
||||
.release_address_v4(gateway.external_interface_address.ip)
|
||||
.expect("must succeed");
|
||||
|
||||
// Update external network
|
||||
machine_registry_inner
|
||||
.network_states_mut()
|
||||
.set_state(external_network_state);
|
||||
}
|
||||
}
|
||||
|
||||
inner.ipv4 = None;
|
||||
// Update fields
|
||||
self.fields = Arc::new(NetworkStateFields {
|
||||
ipv4: None,
|
||||
address_pool,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_ipv4(
|
||||
&self,
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
params: NetworkStateIpv4Params,
|
||||
gateway_params: Option<NetworkStateIpv4GatewayParams>,
|
||||
) -> MachineRegistryResult<()> {
|
||||
Self::clear_ipv4_inner(self.id(), &mut *inner, machine_registry_inner)?;
|
||||
self.clear_ipv4(machine_registry_inner)?;
|
||||
|
||||
inner.address_pool.add_scope_v4(params.allocation);
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
address_pool.add_scope_v4(params.allocation);
|
||||
|
||||
let gateway = match gateway_params {
|
||||
Some(gateway_params) => {
|
||||
// Allocate or reserve an internal network address for the gateway
|
||||
let internal_address =
|
||||
if let Some(internal_address) = gateway_params.internal_address {
|
||||
inner.address_pool.reserve_allocation_v4(
|
||||
address_pool.reserve_allocation_v4(
|
||||
Ipv4Net::new(internal_address, 32).expect("must succeed"),
|
||||
Some(OwnerTag::Gateway(self.id())),
|
||||
)?;
|
||||
internal_address
|
||||
} else {
|
||||
let Some(internal_address) = inner.address_pool.allocate_random_v4(
|
||||
let Some(internal_address) = address_pool.allocate_random_v4(
|
||||
machine_registry_inner.srng(),
|
||||
32,
|
||||
OwnerTag::Gateway(self.id()),
|
||||
@ -230,7 +243,7 @@ impl NetworkState {
|
||||
};
|
||||
|
||||
// Get the external network state
|
||||
let external_network_state = machine_registry_inner
|
||||
let mut external_network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(gateway_params.external_network)
|
||||
.expect("must succeed");
|
||||
@ -255,6 +268,11 @@ impl NetworkState {
|
||||
)?
|
||||
};
|
||||
|
||||
// Update external network
|
||||
machine_registry_inner
|
||||
.network_states_mut()
|
||||
.set_state(external_network_state);
|
||||
|
||||
// Return the gateway state
|
||||
Some(NetworkStateIpv4Gateway {
|
||||
params: gateway_params,
|
||||
@ -267,38 +285,85 @@ impl NetworkState {
|
||||
|
||||
let ipv4 = NetworkStateIpv4 { params, gateway };
|
||||
|
||||
inner.ipv4 = Some(ipv4);
|
||||
// Update fields
|
||||
self.fields = Arc::new(NetworkStateFields {
|
||||
ipv4: Some(ipv4),
|
||||
address_pool,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clear_ipv6(
|
||||
&self,
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
) -> MachineRegistryResult<()> {
|
||||
Self::clear_ipv6_inner(self.id(), &mut *inner, machine_registry_inner)
|
||||
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(),
|
||||
})?;
|
||||
|
||||
// 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
|
||||
.network_states()
|
||||
.get_state(gateway.params.external_network)
|
||||
.expect("must succeed");
|
||||
|
||||
// Release external address
|
||||
external_network_state
|
||||
.release_address_v6(gateway.external_interface_address.ip)
|
||||
.expect("must succeed");
|
||||
|
||||
// Update external network
|
||||
machine_registry_inner
|
||||
.network_states_mut()
|
||||
.set_state(external_network_state);
|
||||
}
|
||||
}
|
||||
|
||||
// Update fields
|
||||
self.fields = Arc::new(NetworkStateFields {
|
||||
ipv6: None,
|
||||
address_pool,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_ipv6(
|
||||
&self,
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
params: NetworkStateIpv6Params,
|
||||
gateway_params: Option<NetworkStateIpv6GatewayParams>,
|
||||
) -> MachineRegistryResult<()> {
|
||||
Self::clear_ipv6_inner(self.id(), &mut *inner, machine_registry_inner)?;
|
||||
self.clear_ipv6(machine_registry_inner)?;
|
||||
|
||||
inner.address_pool.add_scope_v6(params.allocation);
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
address_pool.add_scope_v6(params.allocation);
|
||||
|
||||
let gateway = match gateway_params {
|
||||
Some(gateway_params) => {
|
||||
// Allocate or reserve an internal network address for the gateway
|
||||
let internal_address =
|
||||
if let Some(internal_address) = gateway_params.internal_address {
|
||||
inner.address_pool.reserve_allocation_v6(
|
||||
address_pool.reserve_allocation_v6(
|
||||
Ipv6Net::new(internal_address, 128).expect("must succeed"),
|
||||
Some(OwnerTag::Gateway(self.id())),
|
||||
)?;
|
||||
internal_address
|
||||
} else {
|
||||
let Some(internal_address) = inner.address_pool.allocate_random_v6(
|
||||
let Some(internal_address) = address_pool.allocate_random_v6(
|
||||
machine_registry_inner.srng(),
|
||||
128,
|
||||
OwnerTag::Gateway(self.id()),
|
||||
@ -317,7 +382,7 @@ impl NetworkState {
|
||||
};
|
||||
|
||||
// Get the external network state
|
||||
let external_network_state = machine_registry_inner
|
||||
let mut external_network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(gateway_params.external_network)
|
||||
.expect("must succeed");
|
||||
@ -342,6 +407,11 @@ impl NetworkState {
|
||||
)?
|
||||
};
|
||||
|
||||
// Update external network
|
||||
machine_registry_inner
|
||||
.network_states_mut()
|
||||
.set_state(external_network_state);
|
||||
|
||||
// Return the gateway state
|
||||
Some(NetworkStateIpv6Gateway {
|
||||
params: gateway_params,
|
||||
@ -354,30 +424,36 @@ impl NetworkState {
|
||||
|
||||
let ipv6 = NetworkStateIpv6 { params, gateway };
|
||||
|
||||
inner.ipv6 = Some(ipv6);
|
||||
// Update fields
|
||||
self.fields = Arc::new(NetworkStateFields {
|
||||
ipv6: Some(ipv6),
|
||||
address_pool,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_ipv4(&self) -> bool {
|
||||
self.fields.lock().ipv4.is_some()
|
||||
self.fields.ipv4.is_some()
|
||||
}
|
||||
|
||||
pub fn is_ipv6(&self) -> bool {
|
||||
self.fields.lock().ipv6.is_some()
|
||||
self.fields.ipv6.is_some()
|
||||
}
|
||||
|
||||
pub fn is_active(&self) -> MachineRegistryResult<bool> {
|
||||
let mut can_allocate = false;
|
||||
|
||||
if inner.ipv4.is_some() {
|
||||
if self.fields.ipv4.is_some() {
|
||||
//
|
||||
if !inner.address_pool.can_allocate_v4(32)? {
|
||||
if !self.fields.address_pool.can_allocate_v4(32)? {
|
||||
can_allocate = false;
|
||||
}
|
||||
}
|
||||
if inner.ipv6.is_some() {
|
||||
if self.fields.ipv6.is_some() {
|
||||
//
|
||||
if !inner.address_pool.can_allocate_v6(128)? {
|
||||
if !self.fields.address_pool.can_allocate_v6(128)? {
|
||||
can_allocate = false;
|
||||
}
|
||||
}
|
||||
@ -390,61 +466,103 @@ impl NetworkState {
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv4Addr>,
|
||||
) -> MachineRegistryResult<Ifv4Addr> {
|
||||
let mut inner = self.fields.lock();
|
||||
|
||||
let net = Self::allocate_net_v4_inner(
|
||||
&mut *inner,
|
||||
machine_registry_inner,
|
||||
owner_tag,
|
||||
opt_address,
|
||||
32,
|
||||
)?;
|
||||
let net = self.allocate_subnet_v4(machine_registry_inner, owner_tag, opt_address, 32)?;
|
||||
let ip = net.addr();
|
||||
|
||||
let ipv4 = self.fields.ipv4.as_ref().unwrap();
|
||||
let netmask = ipv4.params.allocation.netmask();
|
||||
let broadcast = ipv4.params.allocation.broadcast();
|
||||
|
||||
let ifaddr = Ifv4Addr {
|
||||
ip,
|
||||
netmask: inner.ipv4.as_ref().unwrap().params.allocation.netmask(),
|
||||
broadcast: Some(inner.ipv4.as_ref().unwrap().params.allocation.broadcast()),
|
||||
netmask,
|
||||
broadcast: Some(broadcast),
|
||||
};
|
||||
|
||||
Ok(ifaddr)
|
||||
}
|
||||
|
||||
pub fn can_allocate_address_v4(&self, opt_address: Option<Ipv4Addr>) -> bool {
|
||||
Self::can_allocate_net_v4_inner(&*inner, opt_address, 32)
|
||||
self.can_allocate_subnet_v4(opt_address, 32)
|
||||
}
|
||||
|
||||
pub fn allocate_subnet_v4(
|
||||
&self,
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv4Addr>,
|
||||
prefix: u8,
|
||||
) -> MachineRegistryResult<Ipv4Net> {
|
||||
let net = Self::allocate_net_v4_inner(
|
||||
&mut *inner,
|
||||
machine_registry_inner,
|
||||
owner_tag,
|
||||
opt_address,
|
||||
prefix,
|
||||
)?;
|
||||
if self.fields.ipv4.is_none() {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
}
|
||||
|
||||
// See if we are requesting a specific address
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
|
||||
let net = if let Some(address) = opt_address {
|
||||
// Get the net form for this address
|
||||
let net = Ipv4Net::new(address, prefix).expect("must succeed");
|
||||
address_pool.reserve_allocation_v4(net, Some(owner_tag))?;
|
||||
net
|
||||
} else {
|
||||
// Get a random address if available
|
||||
let Some(allocation) = address_pool.allocate_random_v4(
|
||||
machine_registry_inner.srng(),
|
||||
prefix,
|
||||
owner_tag,
|
||||
)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
allocation
|
||||
};
|
||||
|
||||
// Update fields
|
||||
self.fields = Arc::new(NetworkStateFields {
|
||||
address_pool,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
|
||||
Ok(net)
|
||||
}
|
||||
|
||||
pub fn can_allocate_subnet_v4(&self, opt_address: Option<Ipv4Addr>, prefix: u8) -> bool {
|
||||
Self::can_allocate_net_v4_inner(&*inner, opt_address, prefix)
|
||||
if self.fields.ipv4.is_none() {
|
||||
return false;
|
||||
};
|
||||
|
||||
// See if we are requesting a specific address
|
||||
if let Some(address) = opt_address {
|
||||
// Get the net form for this address
|
||||
let net = Ipv4Net::new(address, prefix).expect("must succeed");
|
||||
self.fields.address_pool.get_overlaps_v4(net).is_empty()
|
||||
} else {
|
||||
// Get a random address if available
|
||||
self.fields
|
||||
.address_pool
|
||||
.can_allocate_v4(prefix)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn release_address_v4(
|
||||
&mut self,
|
||||
addr: Ipv4Addr,
|
||||
) -> MachineRegistryResult<Option<OwnerTag>> {
|
||||
Self::release_subnet_v4_inner(&mut *inner, Ipv4Net::new(addr, 32).expect("must succeed"))
|
||||
self.release_subnet_v4(Ipv4Net::new(addr, 32).expect("must succeed"))
|
||||
}
|
||||
|
||||
pub fn release_subnet_v4(&mut self, net: Ipv4Net) -> MachineRegistryResult<Option<OwnerTag>> {
|
||||
Self::release_subnet_v4_inner(&mut *inner, net)
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
let opt_tag = address_pool.release_allocation_v4(net)?;
|
||||
|
||||
// Update fields
|
||||
self.fields = Arc::new(NetworkStateFields {
|
||||
address_pool,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
Ok(opt_tag)
|
||||
}
|
||||
|
||||
pub fn allocate_address_v6(
|
||||
@ -453,157 +571,69 @@ impl NetworkState {
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv6Addr>,
|
||||
) -> MachineRegistryResult<Ifv6Addr> {
|
||||
let net = Self::allocate_net_v6_inner(
|
||||
&mut *inner,
|
||||
machine_registry_inner,
|
||||
owner_tag,
|
||||
opt_address,
|
||||
128,
|
||||
)?;
|
||||
let net = self.allocate_subnet_v6(machine_registry_inner, owner_tag, opt_address, 128)?;
|
||||
let ip = net.addr();
|
||||
|
||||
let ipv6 = self.fields.ipv6.as_ref().unwrap();
|
||||
let netmask = ipv6.params.allocation.netmask();
|
||||
let broadcast = ipv6.params.allocation.broadcast();
|
||||
|
||||
let ifaddr = Ifv6Addr {
|
||||
ip,
|
||||
netmask: inner.ipv6.as_ref().unwrap().params.allocation.netmask(),
|
||||
broadcast: Some(inner.ipv6.as_ref().unwrap().params.allocation.broadcast()),
|
||||
netmask,
|
||||
broadcast: Some(broadcast),
|
||||
};
|
||||
|
||||
Ok(ifaddr)
|
||||
}
|
||||
|
||||
pub fn can_allocate_address_v6(&self, opt_address: Option<Ipv6Addr>) -> bool {
|
||||
Self::can_allocate_net_v6_inner(&*inner, opt_address, 128)
|
||||
self.can_allocate_subnet_v6(opt_address, 128)
|
||||
}
|
||||
|
||||
pub fn allocate_subnet_v6(
|
||||
&self,
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv6Addr>,
|
||||
prefix: u8,
|
||||
) -> MachineRegistryResult<Ipv6Net> {
|
||||
let net = Self::allocate_net_v6_inner(
|
||||
&mut *inner,
|
||||
machine_registry_inner,
|
||||
owner_tag,
|
||||
opt_address,
|
||||
prefix,
|
||||
)?;
|
||||
if self.fields.ipv6.is_none() {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
}
|
||||
|
||||
// See if we are requesting a specific address
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
|
||||
let net = if let Some(address) = opt_address {
|
||||
// Get the net form for this address
|
||||
let net = Ipv6Net::new(address, prefix).expect("must succeed");
|
||||
address_pool.reserve_allocation_v6(net, Some(owner_tag))?;
|
||||
net
|
||||
} else {
|
||||
// Get a random address if available
|
||||
let Some(allocation) = address_pool.allocate_random_v6(
|
||||
machine_registry_inner.srng(),
|
||||
prefix,
|
||||
owner_tag,
|
||||
)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
allocation
|
||||
};
|
||||
|
||||
// Update fields
|
||||
self.fields = Arc::new(NetworkStateFields {
|
||||
address_pool,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
|
||||
Ok(net)
|
||||
}
|
||||
|
||||
pub fn can_allocate_subnet_v6(&self, opt_address: Option<Ipv6Addr>, prefix: u8) -> bool {
|
||||
Self::can_allocate_net_v6_inner(&*inner, opt_address, prefix)
|
||||
}
|
||||
|
||||
pub fn release_address_v6(&self, addr: Ipv6Addr) -> MachineRegistryResult<Option<OwnerTag>> {
|
||||
Self::release_subnet_v6_inner(&mut *inner, Ipv6Net::new(addr, 128).expect("must succeed"))
|
||||
}
|
||||
|
||||
pub fn release_subnet_v6(&self, net: Ipv6Net) -> MachineRegistryResult<Option<OwnerTag>> {
|
||||
Self::release_subnet_v6_inner(&mut *inner, net)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
fn clear_ipv6_inner(
|
||||
self_id: NetworkStateId,
|
||||
inner: &mut NetworkStateFields,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
) -> MachineRegistryResult<()> {
|
||||
let Some(ipv6) = inner.ipv6.as_mut() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
inner.address_pool.clear_ipv6(|_n, t| match t {
|
||||
OwnerTag::Machine(_) => true,
|
||||
OwnerTag::Network(nsid) => *nsid != self_id,
|
||||
OwnerTag::Gateway(nsid) => *nsid != self_id,
|
||||
})?;
|
||||
|
||||
// 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 external_network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(gateway.params.external_network)
|
||||
.expect("must succeed");
|
||||
|
||||
// Release external address
|
||||
external_network_state
|
||||
.release_address_v6(gateway.external_interface_address.ip)
|
||||
.expect("must succeed");
|
||||
}
|
||||
}
|
||||
|
||||
inner.ipv6 = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn allocate_net_v4_inner(
|
||||
inner: &mut NetworkStateFields,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv4Addr>,
|
||||
prefix: u8,
|
||||
) -> MachineRegistryResult<Ipv4Net> {
|
||||
let Some(_network_state_ipv4) = &mut inner.ipv4 else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
|
||||
// See if we are requesting a specific address
|
||||
let net = if let Some(address) = opt_address {
|
||||
// Get the net form for this address
|
||||
let net = Ipv4Net::new(address, prefix).expect("must succeed");
|
||||
inner
|
||||
.address_pool
|
||||
.reserve_allocation_v4(net, Some(owner_tag))?;
|
||||
net
|
||||
} else {
|
||||
// Get a random address if available
|
||||
let Some(allocation) = inner.address_pool.allocate_random_v4(
|
||||
machine_registry_inner.srng(),
|
||||
prefix,
|
||||
owner_tag,
|
||||
)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
allocation
|
||||
};
|
||||
|
||||
Ok(net)
|
||||
}
|
||||
|
||||
fn can_allocate_net_v4_inner(
|
||||
inner: &NetworkStateFields,
|
||||
opt_address: Option<Ipv4Addr>,
|
||||
prefix: u8,
|
||||
) -> bool {
|
||||
let Some(_network_state_ipv4) = &inner.ipv4 else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// See if we are requesting a specific address
|
||||
if let Some(address) = opt_address {
|
||||
// Get the net form for this address
|
||||
let net = Ipv4Net::new(address, prefix).expect("must succeed");
|
||||
inner.address_pool.get_overlaps_v4(net).is_empty()
|
||||
} else {
|
||||
// Get a random address if available
|
||||
inner.address_pool.can_allocate_v4(prefix).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn can_allocate_net_v6_inner(
|
||||
inner: &NetworkStateFields,
|
||||
opt_address: Option<Ipv6Addr>,
|
||||
prefix: u8,
|
||||
) -> bool {
|
||||
let Some(_network_state_ipv6) = &inner.ipv6 else {
|
||||
if self.fields.ipv6.is_none() {
|
||||
return false;
|
||||
};
|
||||
|
||||
@ -611,97 +641,34 @@ impl NetworkState {
|
||||
if let Some(address) = opt_address {
|
||||
// Get the net form for this address
|
||||
let net = Ipv6Net::new(address, prefix).expect("must succeed");
|
||||
inner.address_pool.get_overlaps_v6(net).is_empty()
|
||||
self.fields.address_pool.get_overlaps_v6(net).is_empty()
|
||||
} else {
|
||||
// Get a random address if available
|
||||
inner.address_pool.can_allocate_v6(prefix).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn allocate_net_v6_inner(
|
||||
inner: &mut NetworkStateFields,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
owner_tag: OwnerTag,
|
||||
opt_address: Option<Ipv6Addr>,
|
||||
prefix: u8,
|
||||
) -> MachineRegistryResult<Ipv6Net> {
|
||||
let Some(_network_state_ipv6) = &mut inner.ipv6 else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
|
||||
// See if we are requesting a specific address
|
||||
let net = if let Some(address) = opt_address {
|
||||
// Get the net form for this address
|
||||
let net = Ipv6Net::new(address, prefix).expect("must succeed");
|
||||
inner
|
||||
self.fields
|
||||
.address_pool
|
||||
.reserve_allocation_v6(net, Some(owner_tag))?;
|
||||
net
|
||||
} else {
|
||||
// Get a random address if available
|
||||
let Some(allocation) = inner.address_pool.allocate_random_v6(
|
||||
machine_registry_inner.srng(),
|
||||
prefix,
|
||||
owner_tag,
|
||||
)?
|
||||
else {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
};
|
||||
allocation
|
||||
};
|
||||
|
||||
Ok(net)
|
||||
}
|
||||
|
||||
fn release_subnet_v4_inner(
|
||||
inner: &mut NetworkStateFields,
|
||||
net: Ipv4Net,
|
||||
) -> MachineRegistryResult<Option<OwnerTag>> {
|
||||
inner.address_pool.release_allocation_v4(net)
|
||||
}
|
||||
|
||||
fn release_subnet_v6_inner(
|
||||
inner: &mut NetworkStateFields,
|
||||
net: Ipv6Net,
|
||||
) -> MachineRegistryResult<Option<OwnerTag>> {
|
||||
inner.address_pool.release_allocation_v6(net)
|
||||
}
|
||||
|
||||
pub fn release_all_addresses<I: Iterator<Item = IpAddr>>(
|
||||
&self,
|
||||
addrs: I,
|
||||
) -> MachineRegistryResult<()> {
|
||||
let mut ok = true;
|
||||
for addr in addrs {
|
||||
match addr {
|
||||
IpAddr::V4(ipv4_addr) => {
|
||||
if Self::release_subnet_v4_inner(
|
||||
&mut *inner,
|
||||
Ipv4Net::new(ipv4_addr, 32).expect("must succeed"),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
IpAddr::V6(ipv6_addr) => {
|
||||
if Self::release_subnet_v6_inner(
|
||||
&mut *inner,
|
||||
Ipv6Net::new(ipv6_addr, 128).expect("must succeed"),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(MachineRegistryError::NoAllocation)
|
||||
.can_allocate_v6(prefix)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn release_address_v6(
|
||||
&mut self,
|
||||
addr: Ipv6Addr,
|
||||
) -> MachineRegistryResult<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>> {
|
||||
let mut address_pool = self.fields.address_pool.clone();
|
||||
let opt_tag = address_pool.release_allocation_v6(net)?;
|
||||
|
||||
// Update fields
|
||||
self.fields = Arc::new(NetworkStateFields {
|
||||
address_pool,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
Ok(opt_tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl State for NetworkState {
|
||||
|
@ -1,15 +1,15 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TemplateStateUnlockedInner {
|
||||
struct TemplateStateImmutable {
|
||||
id: TemplateStateId,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct PerNetworkInfo {
|
||||
limit_machine_count: Option<usize>,
|
||||
machines: HashSet<MachineStateId>,
|
||||
machines: imbl::HashSet<MachineStateId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -18,20 +18,20 @@ enum BlueprintAvailability {
|
||||
Generate(BlueprintState),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TemplateStateInner {
|
||||
#[derive(Debug, Clone)]
|
||||
struct TemplateStateFields {
|
||||
limit_machine_count: Option<usize>,
|
||||
limit_machines_per_network: Option<WeightedList<usize>>,
|
||||
locations_list: Option<MachineLocationsList>,
|
||||
machines: HashSet<MachineStateId>,
|
||||
machines_per_network: HashMap<NetworkStateId, PerNetworkInfo>,
|
||||
disable_capabilities: Vec<String>,
|
||||
machines: imbl::HashSet<MachineStateId>,
|
||||
machines_per_network: imbl::HashMap<NetworkStateId, PerNetworkInfo>,
|
||||
disable_capabilities: imbl::Vector<Arc<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TemplateState {
|
||||
unlocked_inner: Arc<TemplateStateUnlockedInner>,
|
||||
inner: Arc<Mutex<TemplateStateInner>>,
|
||||
immutable: Arc<TemplateStateImmutable>,
|
||||
fields: Arc<TemplateStateFields>,
|
||||
}
|
||||
|
||||
pub type TemplateStateId = StateId<TemplateState>;
|
||||
@ -39,61 +39,85 @@ pub type TemplateStateId = StateId<TemplateState>;
|
||||
impl TemplateState {
|
||||
pub fn new(id: TemplateStateId, name: String) -> Self {
|
||||
Self {
|
||||
unlocked_inner: Arc::new(TemplateStateUnlockedInner { id, name }),
|
||||
inner: Arc::new(Mutex::new(TemplateStateInner {
|
||||
immutable: Arc::new(TemplateStateImmutable { id, name }),
|
||||
fields: Arc::new(TemplateStateFields {
|
||||
limit_machine_count: None,
|
||||
limit_machines_per_network: None,
|
||||
locations_list: None,
|
||||
machines: HashSet::new(),
|
||||
machines_per_network: HashMap::new(),
|
||||
disable_capabilities: Vec::new(),
|
||||
})),
|
||||
machines: imbl::HashSet::new(),
|
||||
machines_per_network: imbl::HashMap::new(),
|
||||
disable_capabilities: imbl::Vector::new(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_disable_capabilities(&self, disable_capabilities: Vec<String>) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.disable_capabilities = disable_capabilities;
|
||||
pub fn set_disable_capabilities(&mut self, disable_capabilities: Vec<String>) {
|
||||
let disable_capabilities =
|
||||
imbl::Vector::from_iter(disable_capabilities.into_iter().map(Arc::new));
|
||||
// Update fields
|
||||
self.fields = Arc::new(TemplateStateFields {
|
||||
disable_capabilities,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_networks_list(&self, networks: WeightedList<NetworkStateId>) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.locations_list = Some(MachineLocationsList::Networks { networks })
|
||||
pub fn set_networks_list(&mut self, networks: WeightedList<NetworkStateId>) {
|
||||
let locations_list = Some(MachineLocationsList::Networks { networks });
|
||||
|
||||
// Update fields
|
||||
self.fields = Arc::new(TemplateStateFields {
|
||||
locations_list,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_blueprints_list(&self, blueprints: WeightedList<BlueprintStateId>) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.locations_list = Some(MachineLocationsList::Blueprints { blueprints })
|
||||
pub fn set_blueprints_list(mut self, blueprints: WeightedList<BlueprintStateId>) {
|
||||
let locations_list = Some(MachineLocationsList::Blueprints { blueprints });
|
||||
|
||||
// Update fields
|
||||
self.fields = Arc::new(TemplateStateFields {
|
||||
locations_list,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn clear_locations_list(&self) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.locations_list = None;
|
||||
pub fn clear_locations_list(&mut self) {
|
||||
let locations_list = None;
|
||||
|
||||
// Update fields
|
||||
self.fields = Arc::new(TemplateStateFields {
|
||||
locations_list,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_limit_machine_count(&self, limit_machine_count: Option<usize>) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.limit_machine_count = limit_machine_count;
|
||||
pub fn set_limit_machine_count(&mut self, limit_machine_count: Option<usize>) {
|
||||
// Update fields
|
||||
self.fields = Arc::new(TemplateStateFields {
|
||||
limit_machine_count,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_limit_machines_per_network(
|
||||
&self,
|
||||
&mut self,
|
||||
limit_machines_per_network: Option<WeightedList<usize>>,
|
||||
) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.limit_machines_per_network = limit_machines_per_network;
|
||||
// Update fields
|
||||
self.fields = Arc::new(TemplateStateFields {
|
||||
limit_machines_per_network,
|
||||
..(*self.fields).clone()
|
||||
});
|
||||
}
|
||||
|
||||
fn is_network_available_inner(
|
||||
inner: &TemplateStateInner,
|
||||
network_state: NetworkState,
|
||||
) -> MachineRegistryResult<bool> {
|
||||
fn is_network_available(&self, network_state: NetworkState) -> MachineRegistryResult<bool> {
|
||||
// If the network is not active, it is not available
|
||||
if !network_state.is_active()? {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Get the per network info
|
||||
let Some(pni) = inner.machines_per_network.get(&network_state.id()) else {
|
||||
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
|
||||
// by definition available
|
||||
return Ok(true);
|
||||
@ -110,8 +134,8 @@ impl TemplateState {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn is_blueprint_available_inner(
|
||||
inner: &TemplateStateInner,
|
||||
fn is_blueprint_available(
|
||||
&self,
|
||||
machine_registry_inner: &MachineRegistryInner,
|
||||
blueprint_state: BlueprintState,
|
||||
) -> MachineRegistryResult<Option<BlueprintAvailability>> {
|
||||
@ -120,7 +144,7 @@ impl TemplateState {
|
||||
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_inner(inner, network_state.clone())? {
|
||||
if self.is_network_available(network_state.clone())? {
|
||||
// We found one
|
||||
return Ok(Some(network_state));
|
||||
}
|
||||
@ -145,16 +169,14 @@ impl TemplateState {
|
||||
&self,
|
||||
machine_registry_inner: &MachineRegistryInner,
|
||||
) -> MachineRegistryResult<bool> {
|
||||
let inner = self.inner.lock();
|
||||
|
||||
// See if we have reached our machine limit
|
||||
if let Some(limit_machine_count) = inner.limit_machine_count {
|
||||
if inner.machines.len() >= limit_machine_count {
|
||||
if let Some(limit_machine_count) = self.fields.limit_machine_count {
|
||||
if self.fields.machines.len() >= limit_machine_count {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
let Some(locations_list) = inner.locations_list.as_ref() else {
|
||||
let Some(locations_list) = self.fields.locations_list.as_ref() else {
|
||||
return Ok(false);
|
||||
};
|
||||
|
||||
@ -165,7 +187,7 @@ impl TemplateState {
|
||||
.try_filter(|id| {
|
||||
let network_state =
|
||||
machine_registry_inner.network_states().get_state(*id)?;
|
||||
Self::is_network_available_inner(&*inner, network_state)
|
||||
self.is_network_available(network_state)
|
||||
})?
|
||||
.is_none()
|
||||
{
|
||||
@ -179,12 +201,8 @@ impl TemplateState {
|
||||
let blueprint_state =
|
||||
machine_registry_inner.blueprint_states().get_state(*id)?;
|
||||
|
||||
Self::is_blueprint_available_inner(
|
||||
&*inner,
|
||||
machine_registry_inner,
|
||||
blueprint_state,
|
||||
)
|
||||
.map(|x| x.is_some())
|
||||
self.is_blueprint_available(machine_registry_inner, blueprint_state)
|
||||
.map(|x| x.is_some())
|
||||
})?
|
||||
.is_none()
|
||||
{
|
||||
@ -200,17 +218,15 @@ impl TemplateState {
|
||||
&mut self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
) -> MachineRegistryResult<MachineStateId> {
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
// See if we have reached our machine limit
|
||||
if let Some(limit_machine_count) = inner.limit_machine_count {
|
||||
if inner.machines.len() < limit_machine_count.try_into().unwrap_or(usize::MAX) {
|
||||
if let Some(limit_machine_count) = self.fields.limit_machine_count {
|
||||
if self.fields.machines.len() < limit_machine_count.try_into().unwrap_or(usize::MAX) {
|
||||
return Err(MachineRegistryError::TemplateComplete);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) = inner.locations_list.as_ref() else {
|
||||
let Some(locations_list) = self.fields.locations_list.as_ref() else {
|
||||
return Err(MachineRegistryError::TemplateComplete);
|
||||
};
|
||||
|
||||
@ -220,7 +236,7 @@ impl TemplateState {
|
||||
// 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)?;
|
||||
if Self::is_network_available_inner(&*inner, network_state.clone())? {
|
||||
if self.is_network_available(network_state.clone())? {
|
||||
Ok(Some(network_state))
|
||||
} else {
|
||||
Ok(None)
|
||||
@ -244,11 +260,7 @@ impl TemplateState {
|
||||
let blueprint_state =
|
||||
machine_registry_inner.blueprint_states().get_state(*id)?;
|
||||
|
||||
Self::is_blueprint_available_inner(
|
||||
&*inner,
|
||||
machine_registry_inner,
|
||||
blueprint_state,
|
||||
)
|
||||
self.is_blueprint_available(machine_registry_inner, blueprint_state)
|
||||
})?
|
||||
else {
|
||||
return Err(MachineRegistryError::BlueprintComplete);
|
||||
@ -270,6 +282,8 @@ impl TemplateState {
|
||||
// Allocate a machine id
|
||||
let machine_state_id = machine_registry_inner.machine_states_mut().allocate_id();
|
||||
|
||||
xxx continue here
|
||||
|
||||
// Create an anonymous machine state
|
||||
let machine_state = MachineState::new(machine_state_id, None);
|
||||
|
||||
@ -309,8 +323,12 @@ impl TemplateState {
|
||||
.machines_per_network
|
||||
.entry(network_state.id())
|
||||
.or_insert_with(|| {
|
||||
let limit_machine_count = limit_machines_per_network
|
||||
.map(|wl| machine_registry_inner.srng().weighted_choice_ref(&wl).clone());
|
||||
let limit_machine_count = limit_machines_per_network.map(|wl| {
|
||||
machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice_ref(&wl)
|
||||
.clone()
|
||||
});
|
||||
PerNetworkInfo {
|
||||
limit_machine_count,
|
||||
machines: HashSet::new(),
|
||||
|
Loading…
Reference in New Issue
Block a user