Skip to content

Commit 85578ea

Browse files
committed
fix: fix traceroute output and tests
1 parent 22a6a0d commit 85578ea

File tree

6 files changed

+100
-79
lines changed

6 files changed

+100
-79
lines changed

src/algorithms/diamond_miner.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ impl DiamondMiner {
8484

8585
// echo replies and destination unreachable replies should count towards successors counts
8686
pub fn links_by_ttl(&self) -> HashMap<TTL, Vec<Link>> {
87-
get_links_by_ttl(&self.replies())
88-
// get_links_by_ttl(&self.time_exceeded_replies())
87+
// get_links_by_ttl(&self.replies())
88+
get_links_by_ttl(&self.time_exceeded_replies())
8989
}
9090

9191
pub fn n_links_by_ttl(&self) -> HashMap<TTL, usize> {
@@ -170,11 +170,17 @@ impl DiamondMiner {
170170
// continue;
171171
// }
172172
// if the node is in the same subnet as the destination
173-
let prefix_length = (32 - (128 - self.mapper_v4.prefix_size.leading_zeros())) as u8;
173+
let prefix_length = (1 + 32 - (128 - self.mapper_v4.prefix_size.leading_zeros())) as u8;
174+
174175
let dst_network =
175176
ip_network::IpNetwork::new_truncate(self.dst_addr, prefix_length).unwrap();
176177

177178
if dst_network.contains(node) {
179+
// println!("network: {:?}", dst_network);
180+
// println!(
181+
// "Node {} is in the same subnet as the destination {}, with prefix length {}",
182+
// node, self.dst_addr, prefix_length
183+
// );
178184
continue;
179185
}
180186

@@ -209,13 +215,13 @@ impl DiamondMiner {
209215
// .filter(|l| l.near_ip == Some(node))
210216
.count();
211217

212-
// if a node has no successors, but is not the destination, it is unresolved
213218
if n_probes >= n_k || node == self.dst_addr {
214219
// node is resolved
215220
continue;
216221
}
217222

218-
if n_probes < n_k && n_successors > 0 {
223+
// if n_probes < n_k && n_successors > 0 {
224+
if n_probes < n_k {
219225
// node is unresolved
220226
unresolved_nodes.insert(node);
221227
if estimate_successors {

src/algorithms/diamond_miner/tests.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const DEST: [&str; 10] = [
3131

3232
fn diamond_miner() -> DiamondMiner {
3333
DiamondMiner::new(
34-
IpAddr::V4(IP[0].parse().unwrap()),
34+
IpAddr::V4(DEST[0].parse().unwrap()),
3535
1,
3636
20,
3737
24000,
@@ -92,9 +92,9 @@ fn test_unresolved_nodes_at_ttl_basic() {
9292
IpAddr::V4(IP[2].parse().unwrap()),
9393
];
9494

95-
// let links_by_ttl = miner.links_by_ttl();
96-
// println!(">> miner.replies_by_round: {:?}", miner.replies_by_round);
97-
// println!(">>links_by_ttl: {:?}", links_by_ttl);
95+
let links_by_ttl = miner.links_by_ttl();
96+
println!(">> miner.replies_by_round: {:?}", miner.replies_by_round);
97+
println!(">>links_by_ttl: {:?}", links_by_ttl);
9898

9999
// we fetch the unresolved nodes at TTL 1
100100
let (unresolved_nodes, max_weighted_threshold) = miner.unresolved_nodes_at_ttl(1, false);
@@ -103,8 +103,9 @@ fn test_unresolved_nodes_at_ttl_basic() {
103103
assert_eq!(
104104
unresolved_nodes.len(),
105105
1,
106-
"Unresolved nodes number. unresolved_nodes: {:?}",
107-
unresolved_nodes
106+
"Unresolved nodes number. unresolved_nodes: {:?}, max_weighted_threshold: {}",
107+
unresolved_nodes,
108+
max_weighted_threshold
108109
);
109110
assert_eq!(max_weighted_threshold, 6, "Max weighted threshold");
110111
assert_eq!(
@@ -180,6 +181,8 @@ fn test_unresolved_nodes_at_ttl_missing_link() {
180181
// we should have IP[1] as unresolved at TTL 1
181182
// since we do not know where the response from IP[3] went through
182183
// we have to hypothesize that IP[3] is a potential successor of IP[1]
184+
// ^^^ this is not true, we would need to hypothesize that all nodes
185+
// at ttl n+1 are connected to all nodes at ttl n
183186
let replies = vec![
184187
reply(1, IP[1], DEST[1]),
185188
reply(1, IP[1], DEST[2]),
@@ -208,16 +211,12 @@ fn test_unresolved_nodes_at_ttl_missing_link() {
208211

209212
assert_eq!(
210213
unresolved_nodes.len(),
211-
1,
214+
// 1,
215+
0,
212216
"Unresolved nodes number. unresolved_nodes: {:?}",
213217
unresolved_nodes
214218
);
215-
assert_eq!(max_weighted_threshold, 11, "Max weighted threshold");
216-
assert_eq!(
217-
unresolved_nodes.into_iter().next().unwrap(),
218-
IpAddr::V4(IP[1].parse().unwrap()),
219-
"Unresolved nodes"
220-
);
219+
assert_eq!(max_weighted_threshold, 0, "Max weighted threshold");
221220
}
222221

223222
fn probes_to_count(probes: Vec<Probe>) -> HashMap<TTL, usize> {

src/classic_traceroute.rs

+62-31
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ use std::net::IpAddr;
55
use anyhow::Result;
66

77
use itertools::Itertools;
8-
use pantrace::formats::internal::Traceroute;
8+
use pantrace::formats::internal::{Traceroute, TracerouteHop};
99
use pantrace::traits::TracerouteWriter;
1010

1111
pub struct ClassicTracerouteWriter<W: Write> {
1212
output: W,
1313
min_ttl: u8,
1414
max_ttl: u8,
1515
dst_addr: IpAddr,
16+
total_flows: usize,
1617
}
1718

1819
impl<W: Write> ClassicTracerouteWriter<W> {
@@ -21,12 +22,14 @@ impl<W: Write> ClassicTracerouteWriter<W> {
2122
min_ttl: u8,
2223
max_ttl: u8,
2324
dst_addr: IpAddr,
25+
total_flows: usize,
2426
) -> ClassicTracerouteWriter<W> {
2527
ClassicTracerouteWriter {
2628
output,
2729
min_ttl,
2830
max_ttl,
2931
dst_addr,
32+
total_flows,
3033
}
3134
}
3235
}
@@ -39,20 +42,37 @@ where
3942
let packet_size = traceroute.flows[0].hops[0].probes[0].size;
4043
write!(
4144
self.output,
42-
"traceroute to {}({}), {} hops max, {} bytes packets",
43-
traceroute.dst_addr, traceroute.dst_addr, self.max_ttl, packet_size
45+
"traceroute to {}({}), {} hops max, {} bytes packets, flow {}/{}\n",
46+
traceroute.dst_addr,
47+
traceroute.dst_addr,
48+
self.max_ttl,
49+
packet_size,
50+
1,
51+
self.total_flows
4452
)
4553
.unwrap();
46-
let flow = &traceroute.flows[0];
47-
let hops_by_ttl = flow.hops.iter().group_by(|hop| hop.ttl);
48-
let hops_by_ttl = hops_by_ttl
49-
.into_iter()
50-
.fold(HashMap::new(), |mut acc, (ttl, hops)| {
51-
acc.insert(ttl, hops.collect_vec());
52-
acc
53-
});
5454

55-
write!(self.output, "\n").unwrap();
55+
let all_hops = traceroute
56+
.flows
57+
.iter()
58+
.flat_map(|flow| flow.hops.iter())
59+
// .map(|flow| &flow.hops)
60+
// .flatten()
61+
.collect::<Vec<_>>();
62+
63+
let hops_by_ttl = all_hops
64+
.into_iter()
65+
.group_by(|hop| hop.ttl)
66+
.into_iter()
67+
.fold(
68+
HashMap::<u8, Vec<&TracerouteHop>>::new(),
69+
|mut acc, (ttl, group)| {
70+
acc.entry(ttl)
71+
.or_insert_with(Vec::new)
72+
.extend(group.into_iter());
73+
acc
74+
},
75+
);
5676

5777
let mut found_dst = false;
5878

@@ -62,29 +82,40 @@ where
6282
}
6383
write!(self.output, "{}", ttl).unwrap();
6484
if let Some(hops) = hops_by_ttl.get(&ttl) {
65-
let hop = &hops[0];
66-
let probes_by_host = hop
67-
.probes
68-
.iter()
69-
.filter(|probe| probe.reply.is_some())
70-
.group_by(|probe| probe.reply.as_ref().map(|r| r.addr));
71-
for (ip, probes) in probes_by_host.into_iter() {
72-
let probes = probes.collect_vec();
73-
if let Some(ip) = ip {
74-
write!(self.output, " {} ({})", ip, ip).unwrap();
75-
for probe in probes.iter() {
76-
let reply = probe.reply.as_ref().unwrap();
77-
write!(self.output, " {:.3} ms", reply.rtt / 10.0).unwrap();
78-
found_dst = found_dst || (ip == self.dst_addr);
79-
}
80-
write!(self.output, "\n").unwrap();
81-
} else {
82-
write!(self.output, " *\n").unwrap();
83-
}
85+
let all_probes = hops
86+
.into_iter()
87+
.flat_map(|hop| hop.probes.iter())
88+
.collect::<Vec<_>>();
89+
let all_replies_by_host = all_probes
90+
.into_iter()
91+
.filter_map(|probe| probe.reply.as_ref().map(|reply| (reply.addr, reply.rtt)))
92+
.fold(
93+
HashMap::<IpAddr, Vec<f64>>::new(),
94+
|mut acc, (addr, rtt)| {
95+
acc.entry(addr).or_insert_with(Vec::new).push(rtt);
96+
acc
97+
},
98+
);
99+
100+
for (ip, rtts) in all_replies_by_host.into_iter() {
101+
found_dst |= ip == self.dst_addr;
102+
103+
write!(self.output, " {} ({})", ip, ip).unwrap();
104+
let mean_rtt = rtts.iter().sum::<f64>() / rtts.len() as f64;
105+
write!(
106+
self.output,
107+
" {:.3} ms ({} probes)",
108+
mean_rtt / 10.0,
109+
rtts.len()
110+
)
111+
.unwrap();
112+
write!(self.output, "\n").unwrap();
84113
}
114+
// write!(self.output, "\n").unwrap();
85115
} else {
86116
write!(self.output, " *\n").unwrap();
87117
}
118+
write!(self.output, "\n").unwrap();
88119
}
89120

90121
Ok(())

src/links/tests.rs

-5
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,6 @@ fn test_get_pairs_by_flow() {
113113
(
114114
flow_2,
115115
vec![
116-
ReplyPair {
117-
ttl: 1,
118-
first_reply: None,
119-
second_reply: Some(&replies[1]),
120-
},
121116
ReplyPair {
122117
ttl: 2,
123118
first_reply: Some(&replies[1]),

src/main.rs

+15-21
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use pantrace::formats::internal::{Protocol, Traceroute};
1414
use pantrace::traits::TracerouteWriter;
1515
use voyage::algorithms::diamond_miner::DiamondMiner;
1616
use voyage::classic_traceroute::ClassicTracerouteWriter;
17-
use voyage::pantrace_builder::{replies_to_pantrace_flows, replies_to_single_pantrace_flow};
17+
use voyage::pantrace_builder::replies_to_pantrace_flows;
1818

1919
use anyhow::Result;
2020
use voyage::probe::probe;
@@ -98,7 +98,7 @@ struct Args {
9898
estimate_successors: bool,
9999

100100
/// Output format
101-
#[arg(short, long, value_enum, default_value_t = OutputFormat::Atlas)]
101+
#[arg(short, long, value_enum, default_value_t = OutputFormat::Traceroute)]
102102
output_format: OutputFormat,
103103

104104
/// Receiver wait time in seconds
@@ -271,7 +271,8 @@ fn main() -> Result<()> {
271271
}
272272
}
273273

274-
let pantrace_flows = replies_to_pantrace_flows(&alg.time_exceeded_replies());
274+
// let pantrace_flows = replies_to_pantrace_flows(&alg.time_exceeded_replies());
275+
let pantrace_flows = replies_to_pantrace_flows(&alg.replies());
275276

276277
let traceroute: Traceroute = Traceroute {
277278
measurement_name: "diamond_miner".to_string(),
@@ -286,18 +287,22 @@ fn main() -> Result<()> {
286287
flows: pantrace_flows,
287288
};
288289

290+
println!(
291+
">>> total probes in flows: {}",
292+
traceroute
293+
.flows
294+
.iter()
295+
.map(|f| f.hops.iter().map(|h| h.probes.len()).sum::<usize>())
296+
.sum::<usize>()
297+
);
298+
289299
match args.output_format {
290300
OutputFormat::Traceroute => {
291301
debug!("--- Traceroute output ---");
292302
let stdout = std::io::stdout();
293-
let classic_traceroute_flow = replies_to_single_pantrace_flow(&alg.replies());
294-
// replies_to_single_pantrace_flow(&alg.time_exceeded_replies());
295-
let traceroute = Traceroute {
296-
flows: vec![classic_traceroute_flow],
297-
..traceroute
298-
};
303+
let total_flows = traceroute.flows.len();
299304
let mut traceroute_writer =
300-
ClassicTracerouteWriter::new(stdout, min_ttl, max_ttl, dst_addr);
305+
ClassicTracerouteWriter::new(stdout, min_ttl, max_ttl, dst_addr, total_flows);
301306
traceroute_writer.write_traceroute(&traceroute)?;
302307
}
303308
OutputFormat::Atlas => {
@@ -361,17 +366,6 @@ fn main() -> Result<()> {
361366
}
362367
}
363368
}
364-
// debug!(
365-
// "Links: {}",
366-
// alg.links_by_ttl()
367-
// .values()
368-
// .flatten()
369-
// .filter(|link| link.near_ip.is_some() && link.far_ip.is_some())
370-
// .unique()
371-
// .map(|link| format!("{:?}", link))
372-
// .collect::<Vec<_>>()
373-
// .join(", ")
374-
// );
375369
}
376370
}
377371

src/pantrace_builder.rs

-4
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,3 @@ pub fn replies_to_pantrace_flows(replies: &[&Reply]) -> Vec<TracerouteFlow> {
6868
.map(|replies| generate_pantrace_traceroute_flow(&replies))
6969
.collect()
7070
}
71-
72-
pub fn replies_to_single_pantrace_flow(replies: &[&Reply]) -> TracerouteFlow {
73-
generate_pantrace_traceroute_flow(replies)
74-
}

0 commit comments

Comments
 (0)