Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure that tcp id is unique for each ip address #49

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions msim/src/sim/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ pub struct NetSim {
host_state: Mutex<HostNetworkState>,
rand: GlobalRng,
time: TimeHandle,

// Stores for each node, what is the next tcp id that should be used.
// This value is monitonically increasing.
next_tcp_id_map: Mutex<HashMap<NodeId, u32>>,

// Stores for each ip, what are the tcp ids that are used.
// When creating new tcp ids, we need to make sure that they are unique.
occupied_ip_tcp_ids: Mutex<HashMap<IpAddr, HashSet<u32>>>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -897,6 +904,7 @@ impl plugin::Simulator for NetSim {
time: time.clone(),
host_state: Default::default(),
next_tcp_id_map: Mutex::new(HashMap::new()),
occupied_ip_tcp_ids: Mutex::new(HashMap::new()),
}
}

Expand Down Expand Up @@ -991,20 +999,44 @@ impl NetSim {
self.time.sleep(delay).await;
}

// Checks if for a particular tcp id, whether it has been used on this address before
// or not.
fn tcp_id_for_ip_exist(existing_tcp_id_set: &HashMap<IpAddr, HashSet<u32>>, tcp_id: u32, ip: &IpAddr) -> bool {
if let Some(existing_tcp_ids) = existing_tcp_id_set.get(ip) {
existing_tcp_ids.contains(&tcp_id)
} else {
false
}
}

/// Get the next unused tcp id for this node.
pub fn next_tcp_id(&self, node: NodeId) -> u32 {
pub fn next_tcp_id(&self, node: NodeId, ip: IpAddr) -> u32 {
let mut map = self.next_tcp_id_map.lock().unwrap();
let mut existing_tcp_id_set = self.occupied_ip_tcp_ids.lock().unwrap();
match map.entry(node) {
Entry::Occupied(mut cur) => {
let cur = cur.get_mut();
// limited to 2^32 - 1 tcp sessions per node per simulation run.
// Also, make sure that the tcp id is never used on this ip address before.
*cur = cur.checked_add(1).unwrap();
while Self::tcp_id_for_ip_exist(&existing_tcp_id_set, *cur, &ip) {
*cur = cur.checked_add(1).unwrap();
}
assert!(existing_tcp_id_set.entry(ip.clone()).or_insert_with(HashSet::new).insert(*cur));
*cur
}
Entry::Vacant(e) => {
// tcp ids start at 1, 0 is used for new connections (see poll_accept_internal)
e.insert(1);
1
// Also, make sure that the tcp id is never used on this ip address before.
// Note that when a node restarts, it uses a new NodeId with the same ip address.
// Therefore, we cannot guarantee uniqueness simply by enforcing uniqueness per node.
let mut cur: u32 = 1;
while Self::tcp_id_for_ip_exist(&existing_tcp_id_set, cur, &ip) {
cur = cur.checked_add(1).unwrap();
}
e.insert(cur);
assert!(existing_tcp_id_set.entry(ip.clone()).or_insert_with(HashSet::new).insert(cur));
cur
}
}
}
Expand All @@ -1026,6 +1058,7 @@ impl std::fmt::Debug for Endpoint {
.field("node", &self.node)
.field("addr", &self.addr)
.field("peer", &self.peer)
.field("proto", &self.proto)
.finish()
}
}
Expand Down Expand Up @@ -1111,7 +1144,7 @@ impl Endpoint {

/// Allocate a new tcp id number for this node. Ids are never reused.
pub fn allocate_local_tcp_id(&self) -> u32 {
let id = self.net.next_tcp_id(self.node);
let id = self.net.next_tcp_id(self.node, self.addr.ip());
trace!(
"Allocate local tcp id {} to node {} address {}",
id,
Expand Down
Loading