fix(stats): support sequence number wraparound in IPDV tracking

Use wrapping arithmetic instead of checked arithmetic to ensure inter-packet delay variation (IPDV) is correctly calculated when sequence numbers wrap from u32::MAX to 0.
This commit is contained in:
Nils Andreas Svee committed 2026-05-17 23:11:26 +07:00
1 parent 64da60d480
commit 0b16ee802d
2 files changed
+113 -10

No files matched your search

+50 -8
View File
@@ -48,10 +48,8 @@ impl IpdvTracker {
if let Some(pair) = self.try_pair(seq) {
pairs.push(pair);
}
if let Some(next) = seq.checked_add(1) {
if let Some(pair) = self.try_pair(next) {
pairs.push(pair);
}
if let Some(pair) = self.try_pair(seq.wrapping_add(1)) {
pairs.push(pair);
}
pairs
}
@@ -66,15 +64,13 @@ impl IpdvTracker {
};
if self.samples.remove(&seq).is_some() {
self.completed_pairs.remove(&seq);
if let Some(next) = seq.checked_add(1) {
self.completed_pairs.remove(&next);
}
self.completed_pairs.remove(&seq.wrapping_add(1));
}
}
}
fn try_pair(&mut self, current_seq: u32) -> Option<CompletedIpdvPair> {
let previous_seq = current_seq.checked_sub(1)?;
let previous_seq = current_seq.wrapping_sub(1);
if !self.completed_pairs.insert(current_seq) {
return None;
@@ -237,6 +233,52 @@ mod tests {
);
}
#[test]
fn ipdv_tracker_completes_wrapped_adjacent_pair() {
let mut tracker = IpdvTracker::new(None);
assert!(tracker.insert(ipdv_sample(u32::MAX, 10)).is_empty());
let pairs = tracker.insert(ipdv_sample(0, 14));
assert_eq!(
pairs,
vec![CompletedIpdvPair {
previous_seq: u32::MAX,
current_seq: 0,
rtt_ipdv_ns: 4,
send_ipdv_ns: None,
receive_ipdv_ns: None,
}]
);
}
#[test]
fn ipdv_tracker_wrap_gap_does_not_complete_pair() {
let mut tracker = IpdvTracker::new(None);
assert!(tracker.insert(ipdv_sample(u32::MAX - 1, 10)).is_empty());
assert!(tracker.insert(ipdv_sample(0, 14)).is_empty());
}
#[test]
fn ipdv_tracker_late_wrapped_previous_completes_pair() {
let mut tracker = IpdvTracker::new(None);
assert!(tracker.insert(ipdv_sample(0, 14)).is_empty());
let pairs = tracker.insert(ipdv_sample(u32::MAX, 10));
assert_eq!(
pairs,
vec![CompletedIpdvPair {
previous_seq: u32::MAX,
current_seq: 0,
rtt_ipdv_ns: 4,
send_ipdv_ns: None,
receive_ipdv_ns: None,
}]
);
}
#[test]
fn ipdv_tracker_duplicate_sequence_does_not_emit_pair_again() {
let mut tracker = IpdvTracker::new(None);