Added bridge replacement

This commit is contained in:
onyinyang 2023-05-04 18:10:50 -04:00
parent a5c3d4f77b
commit 8db01700f3
No known key found for this signature in database
GPG Key ID: 156A6435430C2036
2 changed files with 127 additions and 4 deletions

View File

@ -224,8 +224,17 @@ pub struct BridgeTable {
/// them. When a new Migration credential is needed, a bucket is /// them. When a new Migration credential is needed, a bucket is
/// removed from this set and used for that purpose. /// removed from this set and used for that purpose.
pub spares: HashSet<u32>, pub spares: HashSet<u32>,
/// bucket ids of "recyclable" buckets. These buckets have not been handed out
/// to users, nor do they have any Migration credentials pointing to
/// them. When a single bridge is needed and there are no more readily available bridges,
/// bridges are taken from a bucket of hot spares, making the unallocated spare bucket empty
/// but still useable as it has not been handed out previously.
pub recyclable: HashSet<u32>,
/// In some instances a single bridge may need to be added to a bucket
/// In some instances a single bridge may need to be added to a bucket
/// In that case, a spare bucket will be removed from the set of spare bridges. One
pub unallocated_bridges: Vec<BridgeLine>,
/// The date the buckets were last encrypted to make the encbucket. /// The date the buckets were last encrypted to make the encbucket.
///
/// The encbucket must be rebuilt each day so that the Bucket /// The encbucket must be rebuilt each day so that the Bucket
/// Reachability credentials in the buckets can be refreshed. /// Reachability credentials in the buckets can be refreshed.
pub date_last_enc: u32, pub date_last_enc: u32,

View File

@ -366,11 +366,125 @@ impl BridgeAuth {
return res; return res;
} }
} }
if !res { // If this is returned, we assume that the bridge wasn't found in the bridge table
// Assume the bridge is new and should be added to unallocated bridges or else a new bucket // and therefore should be treated as a "new bridge"
res
}
pub fn bridge_replace(
&mut self,
bridge: &BridgeLine,
available_bridge: Option<&BridgeLine>,
bdb: &mut BridgeDb,
) -> bool {
let mut res: bool = false;
let reachable_bridges = &self.bridge_table.reachable.clone();
if let Some(positions) = reachable_bridges.get(bridge) {
for (bucketnum, offset) in positions.iter() {
// Remove the bridge from the bucket
assert!(self.bridge_table.buckets[*bucketnum as usize][*offset] == *bridge);
self.bridge_table.reachable.remove(bridge);
if available_bridge.is_some() {
self.bridge_table.buckets[*bucketnum as usize][*offset] =
*available_bridge.unwrap();
// Remove the bridge from the reachable bridges and add new bridge
self.bridge_table
.reachable
.insert(*available_bridge.unwrap(), positions.clone());
res = true
} else if !self.bridge_table.unallocated_bridges.is_empty() {
self.bridge_table.buckets[*bucketnum as usize][*offset] =
self.bridge_table.unallocated_bridges.pop().unwrap();
// Remove the bridge from the reachable bridges and add new bridge
self.bridge_table.reachable.insert(
self.bridge_table.unallocated_bridges.pop().unwrap(),
positions.clone(),
);
res = true
} else if !self.bridge_table.spares.is_empty() {
// Get the first spare and remove it from the spares
// set.
let spare = *self.bridge_table.spares.iter().next().unwrap();
self.bridge_table.spares.remove(&spare);
// Indicate the removed bucket as a recyclable bucket
self.bridge_table.recyclable.insert(spare);
// Get the actual bridges from the spare bucket
let mut replacement: &BridgeLine = &BridgeLine::default();
// Make the first spare the replacement bridge, add the others to the set of
// unallocated_bridges
let spare_bucket = self.bridge_table.buckets[spare as usize].clone();
for spare_bridge in spare_bucket.iter() {
if replacement.port > 0 {
self.bridge_table.unallocated_bridges.push(*spare_bridge);
} else {
replacement = spare_bridge;
}
}
self.bridge_table.buckets[*bucketnum as usize][*offset] = *replacement;
self.bridge_table
.reachable
.insert(*replacement, positions.clone());
res = true
}
// If there are no available bridges that can be assigned here, the only thing
// that can be done is return an indication that updating the gone bridge
// didn't work.
// Now we should check that the bucket hasn't become "blocked" due to having no available
// bridges
if !res {
// Count how many bridges in this bucket are reachable
let numreachable = self.bridge_table.buckets[*bucketnum as usize]
.iter()
.filter(|br| self.bridge_table.reachable.get(br).is_some())
.count();
// Is this bucket an open-invitation bucket?
if bdb.openinv_buckets.contains(bucketnum) {
bdb.openinv_buckets.remove(bucketnum);
self.trustup_migration_table.table.remove(bucketnum);
continue;
}
// Has the bucket fallen below the
// threshold?
if numreachable == MIN_BUCKET_REACHABILITY {
// This bucket is now unreachable. Get a spare bucket
if self.bridge_table.spares.is_empty() {
// Uh, oh. No spares available. Just delete any
// migrations leading to this bucket.
self.trustup_migration_table
.table
.retain(|_, &mut v| v != *bucketnum);
self.blockage_migration_table
.table
.retain(|_, &mut v| v != *bucketnum);
} else {
// Get the first spare and remove it from the spares
// set.
let spare = *self.bridge_table.spares.iter().next().unwrap();
self.bridge_table.spares.remove(&spare);
// Add a blockage migration from this bucket to the spare
self.blockage_migration_table
.table
.insert(*bucketnum, spare);
// Remove any trust upgrade migrations to this
// bucket
self.trustup_migration_table
.table
.retain(|_, &mut v| v != *bucketnum);
// Change any blockage migrations with this bucket
// as the destination to the spare
for (_, v) in self.blockage_migration_table.table.iter_mut() {
if *v == *bucketnum {
*v = spare;
}
}
}
}
}
}
} }
res res
} }