[skip ci] correct addresspool implementation

This commit is contained in:
Christien Rioux 2024-12-19 11:04:14 -05:00
parent f09b367d05
commit 657b66815d
8 changed files with 554 additions and 94 deletions

View File

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

View File

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

View File

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

View File

@ -33,6 +33,7 @@ pub enum MachineRegistryError {
NetworkNotFound,
TemplateNotFound,
BlueprintNotFound,
ModelNotFound,
NoAllocation,
}

View File

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

View File

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

View File

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

View File

@ -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)?;
}