Fix up replace function, remove recyclable

This commit is contained in:
onyinyang 2023-06-20 17:07:51 -04:00
parent 607ecd89c7
commit 0ede04164b
No known key found for this signature in database
GPG Key ID: 156A6435430C2036
4 changed files with 35 additions and 63 deletions

View File

@ -213,7 +213,7 @@ impl BridgeLine {
#[serde_as] #[serde_as]
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
pub struct BridgeTable { pub struct BridgeTable {
// All structures in the bridgetable are indexed by counter // All structures in the bridgetable are indexed by counter
pub counter: u32, pub counter: u32,
pub keys: HashMap<u32, [u8; 16]>, pub keys: HashMap<u32, [u8; 16]>,
pub buckets: HashMap<u32, [BridgeLine; MAX_BRIDGES_PER_BUCKET]>, pub buckets: HashMap<u32, [BridgeLine; MAX_BRIDGES_PER_BUCKET]>,
@ -226,13 +226,6 @@ 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 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 /// In that case, a spare bucket will be removed from the set of spare bridges. One
pub unallocated_bridges: Vec<BridgeLine>, pub unallocated_bridges: Vec<BridgeLine>,
@ -251,26 +244,6 @@ impl BridgeTable {
self.buckets.len() self.buckets.len()
} }
// TODO Don't need with hashmaps, but remove unused buckets
pub fn recycle_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET], index: u32) {
// Pick a random key to encrypt this bucket
let mut rng = rand::thread_rng();
let mut key: [u8; 16] = [0; 16];
rng.fill_bytes(&mut key);
let key = self.keys.get(&index).unwrap();
let bucket = *self.buckets.get(&index).unwrap();
for (i, bridgeline) in bucket.iter().enumerate() {
if bridgeline.port > 0 {
if let Some(v) = self.reachable.get_mut(bridgeline) {
v.push((index, i));
} else {
let v = vec![(index, i)];
self.reachable.insert(*bridgeline, v);
}
}
}
}
/// Append a new bucket to the bridge table, returning its index /// Append a new bucket to the bridge table, returning its index
pub fn new_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET]) -> u32 { pub fn new_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET]) -> u32 {
// Pick a random key to encrypt this bucket // Pick a random key to encrypt this bucket
@ -308,7 +281,7 @@ impl BridgeTable {
self.encbuckets.clear(); self.encbuckets.clear();
// We want id to be a u32, so we use .zip(0u32..) instead of // We want id to be a u32, so we use .zip(0u32..) instead of
// enumerate() // enumerate()
for (uid, key) in self.keys.iter(){ for (uid, key) in self.keys.iter() {
let bucket = self.buckets.get(uid).unwrap(); let bucket = self.buckets.get(uid).unwrap();
let mut encbucket: [u8; ENC_BUCKET_BYTES] = [0; ENC_BUCKET_BYTES]; let mut encbucket: [u8; ENC_BUCKET_BYTES] = [0; ENC_BUCKET_BYTES];
let plainbucket: [u8; BUCKET_BYTES] = BridgeLine::bucket_encode( let plainbucket: [u8; BUCKET_BYTES] = BridgeLine::bucket_encode(

View File

@ -301,13 +301,7 @@ impl BridgeAuth {
bdb: &mut BridgeDb, bdb: &mut BridgeDb,
) { ) {
let bnum: u32; let bnum: u32;
if self.bridge_table.recyclable.is_empty() {
bnum = self.bridge_table.new_bucket(&bridges); bnum = self.bridge_table.new_bucket(&bridges);
} else {
bnum = *self.bridge_table.recyclable.iter().next().unwrap();
self.bridge_table.recyclable.remove(&bnum);
self.bridge_table.recycle_bucket(&bridges, bnum)
}
let mut single = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; let mut single = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
for b in bridges.iter() { for b in bridges.iter() {
single[0] = *b; single[0] = *b;
@ -320,13 +314,7 @@ impl BridgeAuth {
/// Insert a hot spare bucket of bridges /// Insert a hot spare bucket of bridges
pub fn add_spare_bucket(&mut self, bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET]) { pub fn add_spare_bucket(&mut self, bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET]) {
let bnum: u32; let bnum: u32;
if self.bridge_table.recyclable.is_empty() {
bnum = self.bridge_table.new_bucket(&bucket); bnum = self.bridge_table.new_bucket(&bucket);
} else {
bnum = *self.bridge_table.recyclable.iter().next().unwrap();
self.bridge_table.recyclable.remove(&bnum);
self.bridge_table.recycle_bucket(&bucket, bnum)
}
self.bridge_table.spares.insert(bnum); self.bridge_table.spares.insert(bnum);
} }
@ -382,22 +370,16 @@ impl BridgeAuth {
println!("Bucket num: {:?} and offset: {:?}", bucketnum, offset); println!("Bucket num: {:?} and offset: {:?}", bucketnum, offset);
let bridgelines = match self.bridge_table.buckets.get(bucketnum) { let bridgelines = match self.bridge_table.buckets.get(bucketnum) {
Some(bridgelines) => *bridgelines, Some(bridgelines) => *bridgelines,
None => return res None => return res,
}; };
assert!( assert!(bridgelines[*offset] == reachable_bridge.0);
bridgelines[*offset]
== reachable_bridge.0
);
bridgelines[*offset] = *bridge; bridgelines[*offset] = *bridge;
self.bridge_table.buckets.insert(*bucketnum, bridgelines); self.bridge_table.buckets.insert(*bucketnum, bridgelines);
let bridgelines = match self.bridge_table.buckets.get(bucketnum) { let bridgelines = match self.bridge_table.buckets.get(bucketnum) {
Some(bridgelines) => *bridgelines, Some(bridgelines) => *bridgelines,
None => return res None => return res,
}; };
assert!( assert!(bridgelines[*offset] != reachable_bridge.0);
bridgelines[*offset]
!= reachable_bridge.0
);
} }
res = true; res = true;
} else { } else {
@ -448,7 +430,8 @@ impl BridgeAuth {
for (bucketnum, offset) in positions.iter() { for (bucketnum, offset) in positions.iter() {
let bridgelines = match self.bridge_table.buckets.get(bucketnum) { let bridgelines = match self.bridge_table.buckets.get(bucketnum) {
Some(bridgelines) => *bridgelines, Some(bridgelines) => *bridgelines,
None => return ReplaceSuccess::NotFound, // This should not happen if the rest of the function is correct, we can assume unwrap will succeed
None => return ReplaceSuccess::NotReplaced,
}; };
assert!(bridgelines[*offset] == *bridge); assert!(bridgelines[*offset] == *bridge);
bridgelines[*offset] = *replacement; bridgelines[*offset] = *replacement;
@ -465,7 +448,13 @@ impl BridgeAuth {
let spare = *self.bridge_table.spares.iter().next().unwrap(); let spare = *self.bridge_table.spares.iter().next().unwrap();
self.bridge_table.spares.remove(&spare); self.bridge_table.spares.remove(&spare);
// Get the actual bridges from the spare bucket // Get the actual bridges from the spare bucket
let spare_bucket = self.bridge_table.buckets[&spare]; let spare_bucket = match self.bridge_table.buckets.remove(&spare) {
Some(spare_bucket) => spare_bucket,
// This should not happen if the rest of the functions are correct, we can assume unwrap will succeed
None => return ReplaceSuccess::NotReplaced,
};
// Remove the spare bucket uid from the keys map
self.bridge_table.keys.remove(&spare);
let mut replacement: &BridgeLine = &BridgeLine::default(); let mut replacement: &BridgeLine = &BridgeLine::default();
// Make the first spare the replacement bridge, add the others to the set of // Make the first spare the replacement bridge, add the others to the set of
// unallocated_bridges // unallocated_bridges
@ -479,7 +468,13 @@ impl BridgeAuth {
} }
} }
for (bucketnum, offset) in positions.iter() { for (bucketnum, offset) in positions.iter() {
self.bridge_table.buckets[*bucketnum as usize][*offset] = *replacement; let bridgelines = match self.bridge_table.buckets.get(&bucketnum) {
Some(bridgelines) => *bridgelines,
None => return ReplaceSuccess::NotReplaced,
};
assert!(bridgelines[*offset] == *bridge);
bridgelines[*offset] = *replacement;
self.bridge_table.buckets.insert(*bucketnum, bridgelines);
self.bridge_table self.bridge_table
.reachable .reachable
.insert(*replacement, positions.clone()); .insert(*replacement, positions.clone());

View File

@ -738,8 +738,8 @@ fn test_bridge_replace() {
// Randomly select a bridge to replace // Randomly select a bridge to replace
let table_size = th.ba.bridge_table.buckets.len(); let table_size = th.ba.bridge_table.buckets.len();
let num = rand::thread_rng().gen_range(0, table_size - 1); let num = rand::thread_rng().gen_range(0, table_size - 1) as u32;
let replaceable_bucket = th.ba.bridge_table.buckets.get(num).unwrap().clone(); let replaceable_bucket = th.ba.bridge_table.buckets.get(&num).unwrap().clone();
let replacement_bridge = &replaceable_bucket[0]; let replacement_bridge = &replaceable_bucket[0];
assert!( assert!(
th.ba th.ba
@ -918,7 +918,8 @@ fn test_mark_unreachable() {
println!("openinv = {:?}\n", th.bdb.openinv_buckets); println!("openinv = {:?}\n", th.bdb.openinv_buckets);
// Mark a bridge in an untrusted bucket as unreachable // Mark a bridge in an untrusted bucket as unreachable
let b6 = th.ba.bridge_table.buckets[6][0]; let bucket6 = th.ba.bridge_table.buckets.get(&6u32).unwrap();
let b6 = bucket6[0];
th.ba.bridge_unreachable(&b6, &mut th.bdb); th.ba.bridge_unreachable(&b6, &mut th.bdb);
println!("spares = {:?}", th.ba.bridge_table.spares); println!("spares = {:?}", th.ba.bridge_table.spares);
@ -928,7 +929,8 @@ fn test_mark_unreachable() {
// Mark another bridge grouped to the same trusted bucket as // Mark another bridge grouped to the same trusted bucket as
// unreachable // unreachable
let b7 = th.ba.bridge_table.buckets[7][0]; let bucket7 = th.ba.bridge_table.buckets.get(&7u32).unwrap();
let b7 = bucket7[0];
th.ba.bridge_unreachable(&b7, &mut th.bdb); th.ba.bridge_unreachable(&b7, &mut th.bdb);
println!("spares = {:?}", th.ba.bridge_table.spares); println!("spares = {:?}", th.ba.bridge_table.spares);
@ -947,8 +949,10 @@ fn test_mark_unreachable() {
.1; .1;
// Block two of the bridges in that target bucket // Block two of the bridges in that target bucket
let bt1 = th.ba.bridge_table.buckets[target as usize][1]; let bucket1 = th.ba.bridge_table.buckets.get(&target).unwrap();
let bt2 = th.ba.bridge_table.buckets[target as usize][2]; let bt1 = bucket1[1];
let bucket2 = th.ba.bridge_table.buckets.get(&target).unwrap();
let bt2 = bucket2[2];
th.ba.bridge_unreachable(&bt1, &mut th.bdb); th.ba.bridge_unreachable(&bt1, &mut th.bdb);
th.ba.bridge_unreachable(&bt2, &mut th.bdb); th.ba.bridge_unreachable(&bt2, &mut th.bdb);