mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-12-24 14:59:31 -05:00
[skip ci] correct addresspool implementation
This commit is contained in:
parent
f09b367d05
commit
657b66815d
@ -128,22 +128,22 @@ blueprints:
|
||||
# with both ipv4 and ipv6 networking
|
||||
direct:
|
||||
ipv4:
|
||||
additional_prefix: 24
|
||||
prefix: 24
|
||||
ipv6:
|
||||
additional_prefix: 64
|
||||
prefix: 64
|
||||
# An ipv4-only subnet of the internet directly attached with no translation
|
||||
direct_ipv4_no_ipv6:
|
||||
ipv4:
|
||||
additional_prefix: 24
|
||||
prefix: 24
|
||||
# An ipv6-only subnet of the internet directly attached with no translation
|
||||
direct_ipv6_no_ipv4:
|
||||
ipv6:
|
||||
additional_prefix: 64
|
||||
prefix: 64
|
||||
# An ipv4-only subnet of the internet attached via NAT
|
||||
nat_ipv4_no_ipv6:
|
||||
ipv4:
|
||||
allocation: "$private"
|
||||
additional_prefix: 0
|
||||
prefix: 24
|
||||
gateway:
|
||||
translation: "port_restricted"
|
||||
upnp: 0.25
|
||||
@ -152,12 +152,12 @@ blueprints:
|
||||
nat_ipv4_direct_ipv6:
|
||||
ipv4:
|
||||
allocation: "$private"
|
||||
additional_prefix: 0
|
||||
prefix: 24
|
||||
gateway:
|
||||
translation: "port_restricted"
|
||||
upnp: 0.25
|
||||
ipv6:
|
||||
additional_prefix: 56
|
||||
prefix: 56
|
||||
|
||||
#################################################################
|
||||
# Allocations
|
||||
|
@ -4,6 +4,10 @@ use ipnet::*;
|
||||
#[derive(Debug)]
|
||||
pub struct AddressPool {
|
||||
srng: StableRng,
|
||||
|
||||
scope_v4: Vec<Ipv4Net>,
|
||||
scope_v6: Vec<Ipv6Net>,
|
||||
|
||||
allocated_v4: Vec<Ipv4Net>,
|
||||
allocated_v6: Vec<Ipv6Net>,
|
||||
}
|
||||
@ -12,90 +16,349 @@ impl AddressPool {
|
||||
pub fn new(srng: StableRng) -> Self {
|
||||
Self {
|
||||
srng,
|
||||
scope_v4: Vec::new(),
|
||||
scope_v6: Vec::new(),
|
||||
allocated_v4: Vec::new(),
|
||||
allocated_v6: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_v4(&self, allocation: &Ipv4Net) -> bool {
|
||||
for x in &self.allocated_v4 {
|
||||
if x.contains(allocation) {
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn add_scope_v4(&mut self, allocation: Ipv4Net) {
|
||||
self.scope_v4.push(allocation);
|
||||
self.scope_v4 = Ipv4Net::aggregate(&self.scope_v4);
|
||||
}
|
||||
|
||||
pub fn add_scope_v6(&mut self, allocation: Ipv6Net) {
|
||||
self.scope_v6.push(allocation);
|
||||
self.scope_v6 = Ipv6Net::aggregate(&self.scope_v6);
|
||||
}
|
||||
|
||||
pub fn is_in_scope_v4(&self, allocation: Ipv4Net) -> bool {
|
||||
for x in &self.scope_v4 {
|
||||
if x.contains(&allocation) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn contains_v6(&self, allocation: &Ipv6Net) -> bool {
|
||||
for x in &self.allocated_v6 {
|
||||
if x.contains(allocation) {
|
||||
pub fn is_in_scope_v6(&self, allocation: Ipv6Net) -> bool {
|
||||
for x in &self.scope_v6 {
|
||||
if x.contains(&allocation) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn add_v4(&mut self, allocation: Ipv4Net) {
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn allocate_v4(&mut self, allocation: Ipv4Net) -> MachineRegistryResult<()> {
|
||||
// Ensure the allocation is in our scope
|
||||
if !self.is_in_scope_v4(allocation) {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
}
|
||||
|
||||
// Add to our allocated pool
|
||||
self.allocated_v4.push(allocation);
|
||||
self.allocated_v4 = Ipv4Net::aggregate(&self.allocated_v4);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_v6(&mut self, allocation: Ipv6Net) {
|
||||
pub fn allocate_v6(&mut self, allocation: Ipv6Net) -> MachineRegistryResult<()> {
|
||||
// Ensure the allocation is in our scope
|
||||
if !self.is_in_scope_v6(allocation) {
|
||||
return Err(MachineRegistryError::NoAllocation);
|
||||
}
|
||||
|
||||
// Add to our allocated pool
|
||||
self.allocated_v6.push(allocation);
|
||||
self.allocated_v6 = Ipv6Net::aggregate(&self.allocated_v6);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_random_subnet_v4(
|
||||
&mut self,
|
||||
allocation: &Ipv4Net,
|
||||
additional_prefix: u8,
|
||||
) -> Option<Ipv4Net> {
|
||||
// Apply the additional prefix
|
||||
let prefix = u8::max(
|
||||
allocation.prefix_len() + additional_prefix,
|
||||
allocation.max_prefix_len(),
|
||||
pub fn get_overlaps_v4(&self, allocation: Ipv4Net) -> Vec<Ipv4Net> {
|
||||
let mut overlaps = Vec::<Ipv4Net>::new();
|
||||
for x in &self.allocated_v4 {
|
||||
if x.contains(&allocation) || allocation.contains(x) {
|
||||
overlaps.push(*x);
|
||||
overlaps = Ipv4Net::aggregate(&overlaps);
|
||||
}
|
||||
}
|
||||
overlaps
|
||||
}
|
||||
|
||||
pub fn get_overlaps_v6(&self, allocation: Ipv6Net) -> Vec<Ipv6Net> {
|
||||
let mut overlaps = Vec::<Ipv6Net>::new();
|
||||
for x in &self.allocated_v6 {
|
||||
if x.contains(&allocation) || allocation.contains(x) {
|
||||
overlaps.push(*x);
|
||||
overlaps = Ipv6Net::aggregate(&overlaps);
|
||||
}
|
||||
}
|
||||
overlaps
|
||||
}
|
||||
|
||||
fn range_in_prefix_32(scope_prefix: u8, iterable_prefix_bits: u8) -> u32 {
|
||||
// If we're allocating addresses, exclude scope's network and broadcast address
|
||||
if scope_prefix + iterable_prefix_bits == 32 {
|
||||
// Subtract two from total
|
||||
if scope_prefix == 0 {
|
||||
// Overflow case
|
||||
0xFFFF_FFFEu32
|
||||
} else {
|
||||
// Non-overflow case
|
||||
(1u32 << iterable_prefix_bits) - 2
|
||||
}
|
||||
} else {
|
||||
// network only iteration
|
||||
1u32 << iterable_prefix_bits
|
||||
}
|
||||
}
|
||||
|
||||
fn range_in_prefix_128(scope_prefix: u8, iterable_prefix_bits: u8) -> u128 {
|
||||
// If we're allocating addresses, exclude scope's network and broadcast address
|
||||
if scope_prefix + iterable_prefix_bits == 128 {
|
||||
// Subtract two from total
|
||||
if scope_prefix == 0 {
|
||||
// Overflow case
|
||||
0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFEu128
|
||||
} else {
|
||||
// Non-overflow case
|
||||
(1u128 << iterable_prefix_bits) - 2
|
||||
}
|
||||
} else {
|
||||
// network only iteration
|
||||
1u128 << iterable_prefix_bits
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate_random_v4(&mut self, prefix: u8) -> Option<Ipv4Net> {
|
||||
// Scope ranges to iterate
|
||||
let mut scope_ranges = Vec::<(Ipv4Net, u8, u32)>::new();
|
||||
let mut total_subnets = 0u32;
|
||||
|
||||
// Build range set from scopes, minus the prefix to allocate
|
||||
for scope in self.scope_v4.iter().copied() {
|
||||
// If the prefix we are looking to allocate doesn't fit in this scope
|
||||
// then we exclude it
|
||||
if scope.prefix_len() > prefix {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the number of prefix bits we can iterate
|
||||
let iterable_prefix_bits = prefix - scope.prefix_len();
|
||||
let iterable_range = Self::range_in_prefix_32(scope.prefix_len(), iterable_prefix_bits);
|
||||
|
||||
// Scope ranges to try
|
||||
scope_ranges.push((scope, iterable_prefix_bits, iterable_range));
|
||||
total_subnets += iterable_range;
|
||||
}
|
||||
if total_subnets == 0 {
|
||||
// No range
|
||||
return None;
|
||||
}
|
||||
|
||||
// Choose a random subnet to start with
|
||||
let chosen_subnet_index = self.srng.next_u32(0, total_subnets - 1);
|
||||
|
||||
// Find the starting scope and starting subnet index within
|
||||
// the scope of the chosen subnet index
|
||||
let mut scope_index = 0usize;
|
||||
let mut scope_start_subnet_index = 0u32;
|
||||
loop {
|
||||
assert!(
|
||||
scope_index < scope_ranges.len(),
|
||||
"should always have chosen a starting point inside a scope"
|
||||
);
|
||||
|
||||
// Get the subnets with this prefix
|
||||
let mut subnets = allocation.subnets(prefix).ok()?.collect::<Vec<Ipv4Net>>();
|
||||
|
||||
// Randomize the subnets
|
||||
self.srng.shuffle_vec(&mut subnets);
|
||||
|
||||
// Pick the first available subnet
|
||||
for subnet in subnets {
|
||||
if !self.contains_v4(&subnet) {
|
||||
self.add_v4(subnet);
|
||||
return Some(subnet);
|
||||
let scope_end_subnet_index = scope_start_subnet_index + scope_ranges[scope_index].2;
|
||||
if chosen_subnet_index < scope_end_subnet_index {
|
||||
break;
|
||||
}
|
||||
|
||||
// chosen starting point is in the next scope
|
||||
scope_index += 1;
|
||||
scope_start_subnet_index = scope_end_subnet_index;
|
||||
}
|
||||
let initial_subnet_index = chosen_subnet_index;
|
||||
let initial_scope_index = scope_index;
|
||||
|
||||
// Iterate forward until we find a free range
|
||||
let mut current_subnet_index = initial_subnet_index;
|
||||
let mut current_scope_index = initial_scope_index;
|
||||
let mut current_scope_start_subnet_index = scope_start_subnet_index;
|
||||
let mut current_scope_end_subnet_index =
|
||||
scope_start_subnet_index + scope_ranges[scope_index].2;
|
||||
|
||||
let opt_allocation = loop {
|
||||
// Get the net at this current subnet index
|
||||
let netbits = u32::from(scope_ranges[current_scope_index].0.network());
|
||||
let subnetbits = if prefix == 32 {
|
||||
// Allocating addresses
|
||||
((current_subnet_index - current_scope_start_subnet_index) + 1) << (32 - prefix)
|
||||
} else {
|
||||
// Allocating subnets
|
||||
(current_subnet_index - current_scope_start_subnet_index) << (32 - prefix)
|
||||
};
|
||||
let net = Ipv4Net::new(Ipv4Addr::from(netbits | subnetbits), prefix)
|
||||
.expect("prefix must be valid");
|
||||
// See if this net is available
|
||||
if self.get_overlaps_v4(net).is_empty() {
|
||||
break Some(net);
|
||||
}
|
||||
// If not, go to the next subnet
|
||||
current_subnet_index += 1;
|
||||
|
||||
// If we got back to the beginning we failed to allocate
|
||||
if current_scope_index == initial_scope_index
|
||||
&& current_subnet_index == initial_subnet_index
|
||||
{
|
||||
break None;
|
||||
}
|
||||
|
||||
// If we've reached the end of this scope then go to the next scope
|
||||
if current_subnet_index == current_scope_end_subnet_index {
|
||||
current_scope_index += 1;
|
||||
// Wrap around
|
||||
if current_scope_index == scope_ranges.len() {
|
||||
current_subnet_index = 0;
|
||||
current_scope_index = 0;
|
||||
current_scope_start_subnet_index = 0;
|
||||
} else {
|
||||
current_scope_start_subnet_index = current_scope_end_subnet_index;
|
||||
}
|
||||
current_scope_end_subnet_index =
|
||||
current_scope_start_subnet_index + scope_ranges[current_scope_index].2;
|
||||
}
|
||||
};
|
||||
|
||||
// If we found a free subnet, add it to our allocations
|
||||
if let Some(allocation) = opt_allocation {
|
||||
// Add to our allocated pool
|
||||
self.allocated_v4.push(allocation);
|
||||
self.allocated_v4 = Ipv4Net::aggregate(&self.allocated_v4);
|
||||
return Some(allocation);
|
||||
}
|
||||
|
||||
// No allocation
|
||||
None
|
||||
}
|
||||
|
||||
pub fn add_random_subnet_v6(
|
||||
&mut self,
|
||||
allocation: &Ipv6Net,
|
||||
additional_prefix: u8,
|
||||
) -> Option<Ipv6Net> {
|
||||
// Apply the additional prefix
|
||||
let prefix = u8::max(
|
||||
allocation.prefix_len() + additional_prefix,
|
||||
allocation.max_prefix_len(),
|
||||
pub fn allocate_random_v6(&mut self, prefix: u8) -> Option<Ipv6Net> {
|
||||
// Scope ranges to iterate
|
||||
let mut scope_ranges = Vec::<(Ipv6Net, u8, u128)>::new();
|
||||
let mut total_subnets = 0u128;
|
||||
|
||||
// Build range set from scopes, minus the prefix to allocate
|
||||
for scope in self.scope_v6.iter().copied() {
|
||||
// If the prefix we are looking to allocate doesn't fit in this scope
|
||||
// then we exclude it
|
||||
if scope.prefix_len() > prefix {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the number of prefix bits we can iterate
|
||||
let iterable_prefix_bits = prefix - scope.prefix_len();
|
||||
let iterable_range =
|
||||
Self::range_in_prefix_128(scope.prefix_len(), iterable_prefix_bits);
|
||||
|
||||
// Scope ranges to try
|
||||
scope_ranges.push((scope, iterable_prefix_bits, iterable_range));
|
||||
total_subnets += iterable_range;
|
||||
}
|
||||
if total_subnets == 0 {
|
||||
// No range
|
||||
return None;
|
||||
}
|
||||
|
||||
// Choose a random subnet to start with
|
||||
let chosen_subnet_index = self.srng.next_u128(0, total_subnets - 1);
|
||||
|
||||
// Find the starting scope and starting subnet index within
|
||||
// the scope of the chosen subnet index
|
||||
let mut scope_index = 0usize;
|
||||
let mut scope_start_subnet_index = 0u128;
|
||||
loop {
|
||||
assert!(
|
||||
scope_index < scope_ranges.len(),
|
||||
"should always have chosen a starting point inside a scope"
|
||||
);
|
||||
|
||||
// Get the subnets with this prefix
|
||||
let mut subnets = allocation.subnets(prefix).ok()?.collect::<Vec<Ipv6Net>>();
|
||||
|
||||
// Randomize the subnets
|
||||
self.srng.shuffle_vec(&mut subnets);
|
||||
|
||||
// Pick the first available subnet
|
||||
for subnet in subnets {
|
||||
if !self.contains_v6(&subnet) {
|
||||
self.add_v6(subnet);
|
||||
return Some(subnet);
|
||||
let scope_end_subnet_index = scope_start_subnet_index + scope_ranges[scope_index].2;
|
||||
if chosen_subnet_index < scope_end_subnet_index {
|
||||
break;
|
||||
}
|
||||
|
||||
// chosen starting point is in the next scope
|
||||
scope_index += 1;
|
||||
scope_start_subnet_index = scope_end_subnet_index;
|
||||
}
|
||||
let initial_subnet_index = chosen_subnet_index;
|
||||
let initial_scope_index = scope_index;
|
||||
|
||||
// Iterate forward until we find a free range
|
||||
let mut current_subnet_index = initial_subnet_index;
|
||||
let mut current_scope_index = initial_scope_index;
|
||||
let mut current_scope_start_subnet_index = scope_start_subnet_index;
|
||||
let mut current_scope_end_subnet_index =
|
||||
scope_start_subnet_index + scope_ranges[scope_index].2;
|
||||
|
||||
let opt_allocation = loop {
|
||||
// Get the net at this current subnet index
|
||||
let netbits = u128::from(scope_ranges[current_scope_index].0.network());
|
||||
let subnetbits = if prefix == 128 {
|
||||
// Allocating addresses
|
||||
((current_subnet_index - current_scope_start_subnet_index) + 1) << (128 - prefix)
|
||||
} else {
|
||||
// Allocating subnets
|
||||
(current_subnet_index - current_scope_start_subnet_index) << (128 - prefix)
|
||||
};
|
||||
let net = Ipv6Net::new(Ipv6Addr::from(netbits | subnetbits), prefix)
|
||||
.expect("prefix must be valid");
|
||||
// See if this net is available
|
||||
if self.get_overlaps_v6(net).is_empty() {
|
||||
break Some(net);
|
||||
}
|
||||
// If not, go to the next subnet
|
||||
current_subnet_index += 1;
|
||||
|
||||
// If we got back to the beginning we failed to allocate
|
||||
if current_scope_index == initial_scope_index
|
||||
&& current_subnet_index == initial_subnet_index
|
||||
{
|
||||
break None;
|
||||
}
|
||||
|
||||
// If we've reached the end of this scope then go to the next scope
|
||||
if current_subnet_index == current_scope_end_subnet_index {
|
||||
current_scope_index += 1;
|
||||
// Wrap around
|
||||
if current_scope_index == scope_ranges.len() {
|
||||
current_subnet_index = 0;
|
||||
current_scope_index = 0;
|
||||
current_scope_start_subnet_index = 0;
|
||||
} else {
|
||||
current_scope_start_subnet_index = current_scope_end_subnet_index;
|
||||
}
|
||||
current_scope_end_subnet_index =
|
||||
current_scope_start_subnet_index + scope_ranges[current_scope_index].2;
|
||||
}
|
||||
};
|
||||
|
||||
// If we found a free subnet, add it to our allocations
|
||||
if let Some(allocation) = opt_allocation {
|
||||
// Add to our allocated pool
|
||||
self.allocated_v6.push(allocation);
|
||||
self.allocated_v6 = Ipv6Net::aggregate(&self.allocated_v6);
|
||||
return Some(allocation);
|
||||
}
|
||||
|
||||
// No allocation
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,9 @@ impl MachineRegistryInner {
|
||||
pub fn srng(&self) -> StableRng {
|
||||
self.unlocked_inner.srng.clone()
|
||||
}
|
||||
pub fn config(&self) -> &config::Config {
|
||||
&self.unlocked_inner.config
|
||||
}
|
||||
|
||||
pub fn execute_config(&self, cfg: config::Config) -> MachineRegistryResult<()> {
|
||||
// Create all networks
|
||||
@ -479,7 +482,7 @@ impl MachineRegistryInner {
|
||||
// pub(super) fn choose_allocation_v4(
|
||||
// &mut self,
|
||||
// allocation: config::Allocation,
|
||||
// additional_prefix: u8,
|
||||
// prefix: u8,
|
||||
// ) -> MachineRegistryResult<Ipv4Net> {
|
||||
// // Get allocation subnet candidates
|
||||
// let mut subnet4 = allocation
|
||||
@ -495,7 +498,7 @@ impl MachineRegistryInner {
|
||||
// // Allocate within the subnet
|
||||
// match self
|
||||
// .address_pool
|
||||
// .add_random_subnet_v4(subnet, additional_prefix)
|
||||
// .add_random_subnet_v4(subnet, prefix)
|
||||
// {
|
||||
// Some(a) => {
|
||||
// // Got a sub-allocation
|
||||
@ -520,7 +523,7 @@ impl MachineRegistryInner {
|
||||
// pub(super) fn choose_allocation_v6(
|
||||
// &mut self,
|
||||
// allocation: config::Allocation,
|
||||
// additional_prefix: u8,
|
||||
// prefix: u8,
|
||||
// ) -> MachineRegistryResult<Ipv6Net> {
|
||||
// // Get allocation subnet candidates
|
||||
// let mut subnet6 = allocation
|
||||
@ -536,7 +539,7 @@ impl MachineRegistryInner {
|
||||
// // Allocate within the subnet
|
||||
// match self
|
||||
// .address_pool
|
||||
// .add_random_subnet_v6(subnet, additional_prefix)
|
||||
// .add_random_subnet_v6(subnet, prefix)
|
||||
// {
|
||||
// Some(a) => {
|
||||
// // Got a sub-allocation
|
||||
|
@ -33,6 +33,7 @@ pub enum MachineRegistryError {
|
||||
NetworkNotFound,
|
||||
TemplateNotFound,
|
||||
BlueprintNotFound,
|
||||
ModelNotFound,
|
||||
NoAllocation,
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use ipnet::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BlueprintStateUnlockedInner {
|
||||
@ -9,14 +10,14 @@ struct BlueprintStateUnlockedInner {
|
||||
#[derive(Debug)]
|
||||
pub struct BlueprintStateIpv4Params {
|
||||
pub allocation: Option<String>,
|
||||
pub additional_prefix: u8,
|
||||
pub prefix: u8,
|
||||
pub gateway: Option<BlueprintStateGatewayParams>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlueprintStateIpv6Params {
|
||||
pub allocation: Option<String>,
|
||||
pub additional_prefix: u8,
|
||||
pub prefix: u8,
|
||||
pub gateway: Option<BlueprintStateGatewayParams>,
|
||||
}
|
||||
|
||||
@ -170,7 +171,24 @@ impl BlueprintState {
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
network_state: NetworkState,
|
||||
) -> MachineRegistryResult<()> {
|
||||
xxx do generation
|
||||
let model_name = match inner.model.clone() {
|
||||
Some(models) => machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice(&models)
|
||||
.clone(),
|
||||
None => machine_registry_inner.config().default_model.clone(),
|
||||
};
|
||||
let Some(model) = machine_registry_inner.config().models.get(&model_name) else {
|
||||
return Err(MachineRegistryError::ModelNotFound);
|
||||
};
|
||||
|
||||
let params = NetworkStateModelParams {
|
||||
latency: Some(model.latency.clone()),
|
||||
distance: model.distance.clone(),
|
||||
loss: model.loss,
|
||||
};
|
||||
network_state.set_model(params);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_ipv4_inner(
|
||||
@ -178,7 +196,49 @@ impl BlueprintState {
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
network_state: NetworkState,
|
||||
) -> MachineRegistryResult<()> {
|
||||
//
|
||||
network_state.clear_ipv4(machine_registry_inner);
|
||||
let Some(ipv4) = inner.ipv4.as_ref() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let allocation = ipv4
|
||||
.params
|
||||
.allocation
|
||||
.clone()
|
||||
.map(|x| {
|
||||
let allocation = machine_registry_inner
|
||||
.config()
|
||||
.allocations
|
||||
.get(&x)
|
||||
.ok_or(MachineRegistryError::InvalidName)?;
|
||||
if let Some(subnet4) = &allocation.subnets.subnet4 {
|
||||
let ipv4net = machine_registry_inner
|
||||
.srng()
|
||||
.weighted_choice(subnet4)
|
||||
.clone();
|
||||
Ok(Some(ipv4net))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
Ok(Some(
|
||||
Ipv4Net::new(Ipv4Addr::UNSPECIFIED, 0).expect("must be valid"),
|
||||
))
|
||||
})?;
|
||||
let Some(allocation) = allocation else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// Do suballocation
|
||||
xxx figure out how to do allocation inside internet vs private network
|
||||
|
||||
let params = NetworkStateIpv4Params { allocation };
|
||||
|
||||
let gateway_params = inner.
|
||||
|
||||
network_state.set_ipv4(, gateway_params);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_ipv6_inner(
|
||||
|
@ -15,7 +15,7 @@ struct MachineStateInner {
|
||||
#[derive(Debug)]
|
||||
pub struct MachineStateInterface {
|
||||
/// The network this interface belongs to
|
||||
pub network_id: NetworkStateId,
|
||||
pub network_id: Option<NetworkStateId>,
|
||||
/// The veilid NetworkInterface state
|
||||
pub network_interface: NetworkInterface,
|
||||
}
|
||||
@ -94,7 +94,6 @@ impl MachineState {
|
||||
|
||||
pub fn allocate_interface(
|
||||
&self,
|
||||
network_id: NetworkStateId,
|
||||
opt_name: Option<String>,
|
||||
opt_interface_flags: Option<InterfaceFlags>,
|
||||
) -> MachineRegistryResult<String> {
|
||||
@ -112,7 +111,7 @@ impl MachineState {
|
||||
inner.interfaces.insert(
|
||||
name.clone(),
|
||||
MachineStateInterface {
|
||||
network_id,
|
||||
network_id: None,
|
||||
network_interface: NetworkInterface {
|
||||
name: name.clone(),
|
||||
flags,
|
||||
@ -143,9 +142,12 @@ impl MachineState {
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
let Some(network_id) = intf.network_id else {
|
||||
return Err(MachineRegistryError::NetworkNotFound);
|
||||
};
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(intf.network_id)?;
|
||||
.get_state(network_id)?;
|
||||
|
||||
// Allocate interface address
|
||||
let is_dynamic = opt_address.is_none();
|
||||
@ -180,9 +182,12 @@ impl MachineState {
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
let Some(network_id) = intf.network_id else {
|
||||
return Err(MachineRegistryError::NetworkNotFound);
|
||||
};
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(intf.network_id)?;
|
||||
.get_state(network_id)?;
|
||||
|
||||
// Allocate interface address
|
||||
let is_dynamic = opt_address.is_none();
|
||||
@ -204,6 +209,47 @@ impl MachineState {
|
||||
Ok(ifv6_addr)
|
||||
}
|
||||
|
||||
pub fn attach_network(
|
||||
&self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
interface: &str,
|
||||
network_id: NetworkStateId,
|
||||
) -> MachineRegistryResult<()> {
|
||||
let mut inner = self.inner.lock();
|
||||
let Some(intf) = inner.interfaces.get_mut(interface) else {
|
||||
return Err(MachineRegistryError::InvalidName);
|
||||
};
|
||||
if intf.network_id.is_some() {
|
||||
self.detach_network(machine_registry_inner, interface);
|
||||
}
|
||||
intf.network_id = Some(network_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn detach_network(
|
||||
&self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
interface: &str,
|
||||
) -> MachineRegistryResult<()> {
|
||||
let mut inner = self.inner.lock();
|
||||
Self::detach_network_inner(&mut *inner, machine_registry_inner, interface)
|
||||
}
|
||||
|
||||
pub fn attached_network_interfaces(
|
||||
&self,
|
||||
network_id: NetworkStateId,
|
||||
) -> MachineRegistryResult<Vec<String>> {
|
||||
let mut out = Vec::new();
|
||||
let inner = self.inner.lock();
|
||||
for intf in &inner.interfaces {
|
||||
if intf.1.network_id == Some(network_id) {
|
||||
out.push(intf.0.clone());
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn release_address(
|
||||
&self,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
@ -215,10 +261,14 @@ impl MachineState {
|
||||
return Err(MachineRegistryError::InvalidName);
|
||||
};
|
||||
|
||||
let Some(network_id) = intf.network_id else {
|
||||
return Err(MachineRegistryError::NetworkNotFound);
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(intf.network_id)?;
|
||||
.get_state(network_id)?;
|
||||
|
||||
// Release the address from the network
|
||||
match address {
|
||||
@ -243,6 +293,19 @@ impl MachineState {
|
||||
Self::release_all_addresses_inner(&mut *inner, machine_registry_inner, interface)
|
||||
}
|
||||
|
||||
fn detach_network_inner(
|
||||
inner: &mut MachineStateInner,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
interface: &str,
|
||||
) -> MachineRegistryResult<()> {
|
||||
Self::release_all_addresses_inner(inner, machine_registry_inner, interface)?;
|
||||
let Some(intf) = inner.interfaces.get_mut(interface) else {
|
||||
return Err(MachineRegistryError::InvalidName);
|
||||
};
|
||||
intf.network_id = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn release_all_addresses_inner(
|
||||
inner: &mut MachineStateInner,
|
||||
machine_registry_inner: &mut MachineRegistryInner,
|
||||
@ -252,10 +315,14 @@ impl MachineState {
|
||||
return Err(MachineRegistryError::InvalidName);
|
||||
};
|
||||
|
||||
let Some(network_id) = intf.network_id else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// Get the network state
|
||||
let network_state = machine_registry_inner
|
||||
.network_states()
|
||||
.get_state(intf.network_id)?;
|
||||
.get_state(network_id)?;
|
||||
|
||||
// Release the addresses from the network
|
||||
for addr in &intf.network_interface.addrs {
|
||||
@ -277,7 +344,7 @@ impl MachineState {
|
||||
interface: &str,
|
||||
) -> MachineRegistryResult<()> {
|
||||
let mut inner = self.inner.lock();
|
||||
Self::release_all_addresses_inner(&mut *inner, machine_registry_inner, interface)?;
|
||||
Self::detach_network_inner(&mut *inner, machine_registry_inner, interface)?;
|
||||
inner
|
||||
.interfaces
|
||||
.remove(interface)
|
||||
|
@ -23,17 +23,22 @@ struct NetworkStateInner {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NetworkStateModel {
|
||||
/// Network latency distribution
|
||||
latency: Option<config::Distribution>,
|
||||
/// Distance simulation metric
|
||||
distance: Option<config::Distance>,
|
||||
/// Packet loss probability
|
||||
loss: Probability,
|
||||
params: NetworkStateModelParams,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NetworkStateIpv4Params {
|
||||
allocation: Ipv4Net,
|
||||
pub struct NetworkStateModelParams {
|
||||
/// Network latency distribution
|
||||
pub latency: Option<config::Distribution>,
|
||||
/// Distance simulation metric
|
||||
pub distance: Option<config::Distance>,
|
||||
/// Packet loss probability
|
||||
pub loss: Probability,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NetworkStateIpv4Params {
|
||||
pub allocation: Ipv4Net,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -44,8 +49,8 @@ struct NetworkStateIpv4 {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NetworkStateIpv6Params {
|
||||
allocation: Ipv6Net,
|
||||
pub struct NetworkStateIpv6Params {
|
||||
pub allocation: Ipv6Net,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
struct NetworkStateIpv6 {
|
||||
@ -55,10 +60,10 @@ struct NetworkStateIpv6 {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NetworkStateGatewayParams {
|
||||
translation: config::Translation,
|
||||
upnp: bool,
|
||||
network: Option<NetworkStateId>,
|
||||
pub struct NetworkStateGatewayParams {
|
||||
pub translation: config::Translation,
|
||||
pub upnp: bool,
|
||||
pub network: Option<NetworkStateId>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -88,10 +93,12 @@ impl NetworkState {
|
||||
inner: Arc::new(Mutex::new(NetworkStateInner {
|
||||
generating_blueprint: None,
|
||||
model: NetworkStateModel {
|
||||
params: NetworkStateModelParams {
|
||||
latency: None,
|
||||
distance: None,
|
||||
loss: 0.0,
|
||||
},
|
||||
},
|
||||
ipv4: None,
|
||||
ipv6: None,
|
||||
})),
|
||||
@ -109,9 +116,38 @@ impl NetworkState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_model(&self, model: NetworkStateModel) {
|
||||
pub fn set_model(&self, params: NetworkStateModelParams) {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.model = model;
|
||||
inner.model = NetworkStateModel { params };
|
||||
}
|
||||
|
||||
pub fn clear_ipv4(&self, machine_registry_inner: &mut MachineRegistryInner) {
|
||||
let mut inner = self.inner.lock();
|
||||
let Some(ipv4) = inner.ipv4.as_mut() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut address_machines = HashMap::<MachineStateId, Vec<Ipv4Addr>>::new();
|
||||
for (k, v) in &ipv4.machine_addresses {
|
||||
address_machines.entry(*v).or_default().push(*k);
|
||||
}
|
||||
for (machine_id, addresses) in address_machines {
|
||||
let machine_state = machine_registry_inner
|
||||
.machine_states()
|
||||
.get_state(machine_id)
|
||||
.expect("must exist");
|
||||
|
||||
let interfaces = machine_state
|
||||
.attached_network_interfaces(self.id())
|
||||
.expect("must exist");
|
||||
for address in addresses {
|
||||
for interface in &interfaces {
|
||||
machine_state
|
||||
.release_address(machine_registry_inner, interface, IpAddr::V4(address))
|
||||
.expect("must succeed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_ipv4(
|
||||
@ -145,6 +181,35 @@ impl NetworkState {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_ipv6(&self, machine_registry_inner: &mut MachineRegistryInner) {
|
||||
let mut inner = self.inner.lock();
|
||||
let Some(ipv6) = inner.ipv6.as_mut() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut address_machines = HashMap::<MachineStateId, Vec<Ipv6Addr>>::new();
|
||||
for (k, v) in &ipv6.machine_addresses {
|
||||
address_machines.entry(*v).or_default().push(*k);
|
||||
}
|
||||
for (machine_id, addresses) in address_machines {
|
||||
let machine_state = machine_registry_inner
|
||||
.machine_states()
|
||||
.get_state(machine_id)
|
||||
.expect("must exist");
|
||||
|
||||
let interfaces = machine_state
|
||||
.attached_network_interfaces(self.id())
|
||||
.expect("must exist");
|
||||
for address in addresses {
|
||||
for interface in &interfaces {
|
||||
machine_state
|
||||
.release_address(machine_registry_inner, interface, IpAddr::V6(address))
|
||||
.expect("must succeed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn set_ipv6(
|
||||
&self,
|
||||
params: NetworkStateIpv6Params,
|
||||
|
@ -289,7 +289,8 @@ impl TemplateState {
|
||||
machine_state.set_bootstrap(false);
|
||||
|
||||
// Make the default route interface
|
||||
let vin0 = machine_state.allocate_interface(network_state.id(), None, None)?;
|
||||
let vin0 = machine_state.allocate_interface(None, None)?;
|
||||
machine_state.attach_network(machine_registry_inner, &vin0, network_state.id())?;
|
||||
if network_state.is_ipv4() {
|
||||
machine_state.allocate_address_ipv4(machine_registry_inner, &vin0, None, None)?;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user