netem_trace/model/delay_per_packet.rs
1//! This module contains some predefined delay per-packet trace models.
2//!
3//! Enabled with feature `delay-per-packet-model` or `model`.
4//!
5//! ## Predefined models
6//!
7//! - [`StaticDelayPerPacket`]: A trace model with static delay.
8//! - [`RepeatedDelayPerPacketPattern`]: A trace model with a repeated delay pattern.
9//! - [`NormalizedDelayPerPacket`]: A trace model whose delay subjects to a normal distribution (can set upper and lower bounds, and can configure it to be truncated with `truncated-normal` feature enabled).
10//!
11//! ## Examples
12//!
13//! An example to build model from configuration:
14//!
15//! ```
16//! # use netem_trace::model::StaticDelayPerPacketConfig;
17//! # use netem_trace::{Delay, DelayPerPacketTrace};
18//! let mut static_delay = StaticDelayPerPacketConfig::new()
19//! .delay(Delay::from_millis(10))
20//! .count(2)
21//! .build();
22//! assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
23//! assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
24//! assert_eq!(static_delay.next_delay(), None);
25//! ```
26//!
27//! A more common use case is to build model from a configuration file (e.g. json file):
28//!
29//! ```
30//! # use netem_trace::model::DelayPerPacketTraceConfig;
31//! # use netem_trace::{Delay, DelayPerPacketTrace};
32//! # #[cfg(feature = "human")]
33//! # let config_file_content = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
34//! // The content would be "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}"
35//! // if the `human` feature is not enabled.
36//! # #[cfg(not(feature = "human"))]
37//! let config_file_content = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
38//! let des: Box<dyn DelayPerPacketTraceConfig> = serde_json::from_str(config_file_content).unwrap();
39//! let mut model = des.into_model();
40//! assert_eq!(
41//! model.next_delay(),
42//! Some(Delay::from_millis(10))
43//! );
44//! assert_eq!(
45//! model.next_delay(),
46//! Some(Delay::from_millis(20))
47//! );
48//! assert_eq!(
49//! model.next_delay(),
50//! Some(Delay::from_millis(10))
51//! );
52//! assert_eq!(
53//! model.next_delay(),
54//! Some(Delay::from_millis(20))
55//! );
56//! assert_eq!(model.next_delay(), None);
57//! ```
58use crate::{Delay, DelayPerPacketTrace};
59use dyn_clone::DynClone;
60
61const DEFAULT_RNG_SEED: u64 = 42; // Some documentation will need corrections if this changes
62
63/// This trait is used to convert a per-packet delay trace configuration into a per-packet delay trace model.
64///
65/// Since trace model is often configured with files and often has inner states which
66/// is not suitable to be serialized/deserialized, this trait makes it possible to
67/// separate the configuration part into a simple struct for serialization/deserialization, and
68/// construct the model from the configuration.
69#[cfg_attr(feature = "serde", typetag::serde)]
70pub trait DelayPerPacketTraceConfig: DynClone + Send + std::fmt::Debug {
71 fn into_model(self: Box<Self>) -> Box<dyn DelayPerPacketTrace>;
72}
73
74dyn_clone::clone_trait_object!(DelayPerPacketTraceConfig);
75
76use rand::{rngs::StdRng, RngCore, SeedableRng};
77use rand_distr::{Distribution, LogNormal, Normal};
78#[cfg(feature = "serde")]
79use serde::{Deserialize, Serialize};
80
81#[cfg(feature = "truncated-normal")]
82use super::solve_truncate::solve;
83
84/// The model of a static per-packet delay trace.
85///
86/// This model always returns the same delay for the given amount of packets.
87///
88/// If the `count` is 0, the delay will be repeated forever.
89///
90/// ## Examples
91///
92/// ```
93/// # use netem_trace::model::StaticDelayPerPacketConfig;
94/// # use netem_trace::{Delay, DelayPerPacketTrace};
95/// let mut static_delay = StaticDelayPerPacketConfig::new()
96/// .delay(Delay::from_millis(10))
97/// .count(2)
98/// .build();
99/// assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
100/// assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
101/// assert_eq!(static_delay.next_delay(), None);
102/// ```
103#[derive(Default, Debug, Clone, Copy, PartialEq)]
104pub struct StaticDelayPerPacket {
105 pub delay: Delay,
106 pub count: usize,
107 current_count: usize,
108}
109
110/// The configuration struct for [`StaticDelayPerPacket`].
111///
112/// See [`StaticDelayPerPacket`] for more details.
113#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
114#[derive(Default, Debug, Clone, Copy, PartialEq)]
115pub struct StaticDelayPerPacketConfig {
116 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
117 #[cfg_attr(
118 all(feature = "serde", feature = "human"),
119 serde(with = "humantime_serde")
120 )]
121 pub delay: Option<Delay>,
122 pub count: usize,
123}
124
125/// The model contains an array of per-packet delay trace models.
126///
127/// Combine multiple per-packet delay trace models into one per-packet delay pattern,
128/// and repeat the pattern for `count` times.
129///
130/// If `count` is 0, the pattern will be repeated forever.
131///
132/// ## Examples
133///
134/// The most common use case is to read from a configuration file and
135/// deserialize it into a [`RepeatedDelayPerPacketPatternConfig`]:
136///
137/// ```
138/// use netem_trace::model::{StaticDelayPerPacketConfig, DelayPerPacketTraceConfig};
139/// use netem_trace::{Delay, DelayPerPacketTrace};
140/// #[cfg(feature = "human")]
141/// let config_file_content = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
142/// // The content would be "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}"
143/// // if the `human` feature is not enabled.
144/// #[cfg(not(feature = "human"))]
145/// let config_file_content = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
146/// let des: Box<dyn DelayPerPacketTraceConfig> = serde_json::from_str(config_file_content).unwrap();
147/// let mut model = des.into_model();
148/// assert_eq!(
149/// model.next_delay(),
150/// Some(Delay::from_millis(10))
151/// );
152/// assert_eq!(
153/// model.next_delay(),
154/// Some(Delay::from_millis(20))
155/// );
156/// assert_eq!(
157/// model.next_delay(),
158/// Some(Delay::from_millis(10))
159/// );
160/// assert_eq!(
161/// model.next_delay(),
162/// Some(Delay::from_millis(20))
163/// );
164/// assert_eq!(model.next_delay(), None);
165/// ```
166///
167/// You can also build manually:
168///
169/// ```
170/// # use netem_trace::model::{StaticDelayPerPacketConfig, DelayPerPacketTraceConfig, RepeatedDelayPerPacketPatternConfig};
171/// # use netem_trace::{Delay, DelayPerPacketTrace};
172/// let pat = vec![
173/// Box::new(
174/// StaticDelayPerPacketConfig::new()
175/// .delay(Delay::from_millis(10))
176/// .count(1),
177/// ) as Box<dyn DelayPerPacketTraceConfig>,
178/// Box::new(
179/// StaticDelayPerPacketConfig::new()
180/// .delay(Delay::from_millis(20))
181/// .count(1),
182/// ) as Box<dyn DelayPerPacketTraceConfig>,
183/// ];
184/// let ser = Box::new(RepeatedDelayPerPacketPatternConfig::new().pattern(pat).count(2)) as Box<dyn DelayPerPacketTraceConfig>;
185/// let ser_str = serde_json::to_string(&ser).unwrap();
186/// #[cfg(feature = "human")]
187/// let json_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
188/// // The content would be "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}"
189/// // if the `human` feature is not enabled.
190/// #[cfg(not(feature = "human"))]
191/// let json_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
192/// assert_eq!(ser_str, json_str);
193/// ```
194#[derive(Default)]
195pub struct RepeatedDelayPerPacketPattern {
196 pub pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>,
197 pub count: usize,
198 current_model: Option<Box<dyn DelayPerPacketTrace>>,
199 current_cycle: usize,
200 current_pattern: usize,
201}
202
203/// The configuration struct for [`RepeatedDelayPerPacketPattern`].
204///
205/// See [`RepeatedDelayPerPacketPattern`] for more details.
206#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
207#[derive(Default, Debug, Clone)]
208pub struct RepeatedDelayPerPacketPatternConfig {
209 pub pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>,
210 pub count: usize,
211}
212
213/// The model of a per-packet delay trace subjects to a normal distribution.
214///
215/// The delay will subject to N(mean, std_dev²), but bounded within [lower_bound, upper_bound] (optional)
216///
217/// If the `count` is 0, the delay will be repeated forever, else it will be repeated `count` times.
218///
219/// ## Examples
220///
221/// A simple example without any bound on delay:
222///
223/// ```
224/// # use netem_trace::model::NormalizedDelayPerPacketConfig;
225/// # use netem_trace::{Delay, DelayPerPacketTrace};
226/// let mut normal_delay = NormalizedDelayPerPacketConfig::new()
227/// .mean(Delay::from_millis(12))
228/// .std_dev(Delay::from_millis(1))
229/// .count(2)
230/// .seed(42)
231/// .build();
232/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12069428)));
233/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12132938)));
234/// assert_eq!(normal_delay.next_delay(), None);
235/// ```
236///
237/// A more complex example with bounds on delay:
238///
239/// ```
240/// # use netem_trace::model::NormalizedDelayPerPacketConfig;
241/// # use netem_trace::{Delay, DelayPerPacketTrace};
242/// let mut normal_delay = NormalizedDelayPerPacketConfig::new()
243/// .mean(Delay::from_millis(12))
244/// .std_dev(Delay::from_millis(1))
245/// .count(2)
246/// .seed(42)
247/// .upper_bound(Delay::from_micros(12100))
248/// .lower_bound(Delay::from_micros(11900))
249/// .build();
250/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12069428)));
251/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12100000)));
252/// assert_eq!(normal_delay.next_delay(), None);
253/// ```
254#[derive(Debug, Clone, Copy, PartialEq)]
255pub struct NormalizedDelayPerPacket<Rng = StdRng>
256where
257 Rng: RngCore,
258{
259 pub mean: Delay,
260 pub std_dev: Delay,
261 pub upper_bound: Option<Delay>,
262 pub lower_bound: Delay,
263 pub seed: u64,
264 pub count: usize,
265 current_count: usize,
266 rng: Rng,
267 normal: Normal<f64>,
268}
269
270/// The configuration struct for [`NormalizedDelayPerPacket`].
271///
272/// See [`NormalizedDelayPerPacket`] for more details.
273#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
274#[derive(Default, Debug, Clone, Copy, PartialEq)]
275pub struct NormalizedDelayPerPacketConfig {
276 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
277 #[cfg_attr(
278 all(feature = "serde", feature = "human"),
279 serde(with = "humantime_serde")
280 )]
281 pub mean: Option<Delay>,
282 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
283 #[cfg_attr(
284 all(feature = "serde", feature = "human"),
285 serde(with = "humantime_serde")
286 )]
287 pub std_dev: Option<Delay>,
288 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
289 #[cfg_attr(
290 all(feature = "serde", feature = "human"),
291 serde(with = "humantime_serde")
292 )]
293 pub upper_bound: Option<Delay>,
294 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
295 #[cfg_attr(
296 all(feature = "serde", feature = "human"),
297 serde(with = "humantime_serde")
298 )]
299 pub lower_bound: Option<Delay>,
300 #[cfg_attr(feature = "serde", serde(default))]
301 pub count: usize,
302 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
303 pub seed: Option<u64>,
304}
305/// The model of a per-packet delay trace subjects to a log-normal distribution.
306///
307/// The delay will subject to Lognormal(μ, σ²), but bounded within [lower_bound, upper_bound] (optional)
308/// The provided mean and std_dev are the one of the log-normal law and not the one of the underlying normal law.
309///
310/// If the `count` is 0, the delay will be repeated forever, else it will be repeated `count` times.
311///
312/// ## Examples
313///
314/// A simple example without any bound on delay:
315///
316/// ```
317/// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
318/// # use netem_trace::{Delay, DelayPerPacketTrace};
319/// let mut log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
320/// .mean(Delay::from_millis(12))
321/// .std_dev(Delay::from_millis(1))
322/// .count(2)
323/// .seed(42)
324/// .build();
325/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12027817)));
326/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12091533)));
327/// assert_eq!(log_normal_delay.next_delay(), None);
328/// ```
329///
330/// A more complex example with bounds on delay:
331///
332/// ```
333/// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
334/// # use netem_trace::{Delay, DelayPerPacketTrace};
335/// let mut log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
336/// .mean(Delay::from_millis(12))
337/// .std_dev(Delay::from_millis(1))
338/// .count(3)
339/// .seed(42)
340/// .upper_bound(Delay::from_micros(12100))
341/// .lower_bound(Delay::from_micros(11900))
342/// .build();
343/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12027817)));
344/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12091533)));
345/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12100000)));
346/// assert_eq!(log_normal_delay.next_delay(), None);
347/// ```
348#[derive(Debug, Clone, Copy, PartialEq)]
349pub struct LogNormalizedDelayPerPacket<Rng = StdRng>
350where
351 Rng: RngCore,
352{
353 pub mean: Delay,
354 pub std_dev: Delay,
355 pub upper_bound: Option<Delay>,
356 pub lower_bound: Delay,
357 pub seed: u64,
358 pub count: usize,
359 current_count: usize,
360 rng: Rng,
361 log_normal: LogNormal<f64>,
362}
363
364/// The configuration struct for [`LogNormalizedDelayPerPacket`].
365///
366/// See [`LogNormalizedDelayPerPacket`] for more details.
367#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
368#[derive(Default, Debug, Clone, Copy, PartialEq)]
369pub struct LogNormalizedDelayPerPacketConfig {
370 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
371 #[cfg_attr(
372 all(feature = "serde", feature = "human"),
373 serde(with = "humantime_serde")
374 )]
375 pub mean: Option<Delay>,
376 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
377 #[cfg_attr(
378 all(feature = "serde", feature = "human"),
379 serde(with = "humantime_serde")
380 )]
381 pub std_dev: Option<Delay>,
382 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
383 #[cfg_attr(
384 all(feature = "serde", feature = "human"),
385 serde(with = "humantime_serde")
386 )]
387 pub upper_bound: Option<Delay>,
388 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
389 #[cfg_attr(
390 all(feature = "serde", feature = "human"),
391 serde(with = "humantime_serde")
392 )]
393 pub lower_bound: Option<Delay>,
394 #[cfg_attr(feature = "serde", serde(default))]
395 pub count: usize,
396 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
397 pub seed: Option<u64>,
398}
399
400impl DelayPerPacketTrace for StaticDelayPerPacket {
401 fn next_delay(&mut self) -> Option<Delay> {
402 if self.count != 0 && self.count == self.current_count {
403 None
404 } else {
405 self.current_count += 1;
406 Some(self.delay)
407 }
408 }
409}
410
411impl DelayPerPacketTrace for RepeatedDelayPerPacketPattern {
412 fn next_delay(&mut self) -> Option<Delay> {
413 if self.pattern.is_empty() || (self.count != 0 && self.current_cycle >= self.count) {
414 None
415 } else {
416 if self.current_model.is_none() {
417 self.current_model = Some(self.pattern[self.current_pattern].clone().into_model());
418 }
419 match self.current_model.as_mut().unwrap().next_delay() {
420 Some(delay) => Some(delay),
421 None => {
422 self.current_model = None;
423 self.current_pattern += 1;
424 if self.current_pattern >= self.pattern.len() {
425 self.current_pattern = 0;
426 self.current_cycle += 1;
427 if self.count != 0 && self.current_cycle >= self.count {
428 return None;
429 }
430 }
431 self.next_delay()
432 }
433 }
434 }
435 }
436}
437
438impl<Rng: RngCore + Send> DelayPerPacketTrace for NormalizedDelayPerPacket<Rng> {
439 fn next_delay(&mut self) -> Option<Delay> {
440 if self.count != 0 && self.count == self.current_count {
441 None
442 } else {
443 self.current_count += 1;
444 let delay = self.normal.sample(&mut self.rng).max(0.0);
445 let mut delay = Delay::from_secs_f64(delay);
446 delay = delay.max(self.lower_bound);
447 if let Some(upper_bound) = self.upper_bound {
448 delay = delay.min(upper_bound);
449 }
450 Some(delay)
451 }
452 }
453}
454
455impl<Rng: RngCore + Send> DelayPerPacketTrace for LogNormalizedDelayPerPacket<Rng> {
456 fn next_delay(&mut self) -> Option<Delay> {
457 if self.count != 0 && self.count == self.current_count {
458 None
459 } else {
460 self.current_count += 1;
461 let delay = self.log_normal.sample(&mut self.rng).max(0.0);
462 let mut delay = Delay::from_secs_f64(delay);
463 delay = delay.max(self.lower_bound);
464 if let Some(upper_bound) = self.upper_bound {
465 delay = delay.min(upper_bound);
466 }
467 Some(delay)
468 }
469 }
470}
471
472impl StaticDelayPerPacketConfig {
473 pub fn new() -> Self {
474 Self {
475 delay: None,
476 count: 0,
477 }
478 }
479
480 pub fn delay(mut self, delay: Delay) -> Self {
481 self.delay = Some(delay);
482 self
483 }
484
485 pub fn count(mut self, count: usize) -> Self {
486 self.count = count;
487 self
488 }
489
490 pub fn build(self) -> StaticDelayPerPacket {
491 StaticDelayPerPacket {
492 delay: self.delay.unwrap_or_else(|| Delay::from_millis(10)),
493 count: self.count,
494 current_count: 0,
495 }
496 }
497}
498
499impl RepeatedDelayPerPacketPatternConfig {
500 pub fn new() -> Self {
501 Self {
502 pattern: vec![],
503 count: 0,
504 }
505 }
506
507 pub fn pattern(mut self, pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>) -> Self {
508 self.pattern = pattern;
509 self
510 }
511
512 pub fn count(mut self, count: usize) -> Self {
513 self.count = count;
514 self
515 }
516
517 pub fn build(self) -> RepeatedDelayPerPacketPattern {
518 RepeatedDelayPerPacketPattern {
519 pattern: self.pattern,
520 count: self.count,
521 current_model: None,
522 current_cycle: 0,
523 current_pattern: 0,
524 }
525 }
526}
527
528impl NormalizedDelayPerPacketConfig {
529 /// Creates an uninitialized config
530 pub fn new() -> Self {
531 Self {
532 mean: None,
533 std_dev: None,
534 upper_bound: None,
535 lower_bound: None,
536 count: 0,
537 seed: None,
538 }
539 }
540
541 /// Sets the mean
542 ///
543 /// If the mean is not set, 10ms will be used.
544 pub fn mean(mut self, mean: Delay) -> Self {
545 self.mean = Some(mean);
546 self
547 }
548
549 /// Sets the standard deviation
550 ///
551 /// If the standard deviation is not set, 0ms will be used.
552 pub fn std_dev(mut self, std_dev: Delay) -> Self {
553 self.std_dev = Some(std_dev);
554 self
555 }
556
557 /// Sets the upper bound
558 ///
559 /// If the upper bound is not set, the upper bound will be the one of [`Delay`].
560 pub fn upper_bound(mut self, upper_bound: Delay) -> Self {
561 self.upper_bound = Some(upper_bound);
562 self
563 }
564
565 /// Sets the lower bound
566 ///
567 /// If the lower bound is not set, 0ms will be used.
568 pub fn lower_bound(mut self, lower_bound: Delay) -> Self {
569 self.lower_bound = Some(lower_bound);
570 self
571 }
572
573 /// Sets the number of packets to repeat
574 ///
575 /// If the count is not set, it will be set to 0 (ie, infinite repeat).
576 pub fn count(mut self, count: usize) -> Self {
577 self.count = count;
578 self
579 }
580
581 /// Set the seed for a random generator
582 ///
583 /// If the seed is not set, `42` will be used.
584 pub fn seed(mut self, seed: u64) -> Self {
585 self.seed = Some(seed);
586 self
587 }
588
589 /// Allows to use a randomly generated seed
590 ///
591 /// This is equivalent to: `self.seed(rand::random())`
592 pub fn random_seed(mut self) -> Self {
593 self.seed = Some(rand::random());
594 self
595 }
596
597 /// Creates a new [`NormalizedDelayPerPacket`] corresponding to this config.
598 ///
599 /// The created model will use [`StdRng`] as source of randomness (the call is equivalent to `self.build_with_rng::<StdRng>()`).
600 /// It should be sufficient for most cases, but [`StdRng`] is not a portable random number generator,
601 /// so one may want to use a portable random number generator like [`ChaCha`](https://crates.io/crates/rand_chacha),
602 /// to this end one can use [`build_with_rng`](Self::build_with_rng).
603 pub fn build(self) -> NormalizedDelayPerPacket {
604 self.build_with_rng()
605 }
606
607 /// Creates a new [`NormalizedDelayPerPacket`] corresponding to this config.
608 ///
609 /// Unlike [`build`](Self::build), this method let you choose the random generator.
610 ///
611 /// # Example
612 /// ```rust
613 /// # use netem_trace::model::NormalizedDelayPerPacketConfig;
614 /// # use netem_trace::{Delay, DelayPerPacketTrace};
615 /// # use rand::rngs::StdRng;
616 /// # use rand_chacha::ChaCha20Rng;
617 ///
618 /// let normal_delay = NormalizedDelayPerPacketConfig::new()
619 /// .mean(Delay::from_millis(12))
620 /// .std_dev(Delay::from_millis(1))
621 /// .count(3)
622 /// .seed(42);
623 ///
624 /// let mut default_build = normal_delay.clone().build();
625 /// let mut std_build = normal_delay.clone().build_with_rng::<StdRng>();
626 /// // ChaCha is deterministic and portable, unlike StdRng
627 /// let mut chacha_build = normal_delay.clone().build_with_rng::<ChaCha20Rng>();
628 ///
629 /// for cha in [12044676, 11754367, 11253775] {
630 /// let default = default_build.next_delay();
631 /// let std = std_build.next_delay();
632 /// let chacha = chacha_build.next_delay();
633 ///
634 /// assert!(default.is_some());
635 /// assert_eq!(default, std);
636 /// assert_ne!(default, chacha);
637 /// assert_eq!(chacha, Some(Delay::from_nanos(cha)));
638 /// }
639 ///
640 /// assert_eq!(default_build.next_delay(), None);
641 /// assert_eq!(std_build.next_delay(), None);
642 /// assert_eq!(chacha_build.next_delay(), None);
643 /// ```
644 pub fn build_with_rng<Rng: RngCore + SeedableRng>(self) -> NormalizedDelayPerPacket<Rng> {
645 let mean = self.mean.unwrap_or_else(|| Delay::from_millis(10));
646 let std_dev = self.std_dev.unwrap_or(Delay::ZERO);
647 let upper_bound = self.upper_bound;
648 let lower_bound = self.lower_bound.unwrap_or(Delay::ZERO);
649 let count = self.count;
650 let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
651 let rng = Rng::seed_from_u64(seed);
652 let delay_mean = mean.as_secs_f64();
653 let delay_std_dev = std_dev.as_secs_f64();
654 let normal: Normal<f64> = Normal::new(delay_mean, delay_std_dev).unwrap();
655 NormalizedDelayPerPacket {
656 mean,
657 std_dev,
658 upper_bound,
659 lower_bound,
660 count,
661 current_count: 0,
662 seed,
663 rng,
664 normal,
665 }
666 }
667}
668
669#[cfg(feature = "truncated-normal")]
670impl NormalizedDelayPerPacketConfig {
671 /// This is another implementation for converting NormalizedPerPacketConfig into NormalizedDelayPerPacket, where the impact
672 /// of truncation (`lower_bound` and `upper_bound` field) on the mathematical expectation of the distribution
673 /// is taking account by modifying the center of the distribution.
674 ///
675 /// ## Examples
676 ///
677 /// ```
678 ///
679 /// # use netem_trace::model::NormalizedDelayPerPacketConfig;
680 /// # use netem_trace::{Delay, DelayPerPacketTrace};
681 ///
682 /// let normal_delay = NormalizedDelayPerPacketConfig::new()
683 /// .mean(Delay::from_millis(12))
684 /// .std_dev(Delay::from_millis(12))
685 /// .count(1_000_000)
686 /// .seed(42);
687 ///
688 /// let mut default_build = normal_delay.clone().build();
689 /// let mut truncate_build = normal_delay.clone().build_truncated();
690 ///
691 /// fn avg_delay(mut model: impl DelayPerPacketTrace) -> Delay {
692 /// let mut count = 0;
693 /// std::iter::from_fn( move ||{
694 /// model.next_delay()
695 /// }).inspect(|_| count += 1).sum::<Delay>() / count
696 /// }
697 ///
698 /// assert_eq!(avg_delay(default_build), Delay::from_nanos(12998335)); // significantly higher than the expected mean
699 /// assert_eq!(avg_delay(truncate_build), Delay::from_nanos(11998818));
700 ///
701 /// let normal_delay = NormalizedDelayPerPacketConfig::new()
702 /// .mean(Delay::from_millis(12))
703 /// .std_dev(Delay::from_millis(12))
704 /// .lower_bound(Delay::from_millis(8))
705 /// .upper_bound(Delay::from_millis(20))
706 /// .count(1_000_000)
707 /// .seed(42);
708 ///
709 /// let mut default_build = normal_delay.clone().build();
710 /// let mut truncate_build = normal_delay.clone().build_truncated();
711 ///
712 /// assert_eq!(avg_delay(default_build), Delay::from_nanos(13234261)); // significantly higher than the expected mean
713 /// assert_eq!(avg_delay(truncate_build), Delay::from_nanos(11999151));
714 ///
715 /// ```
716 pub fn build_truncated(self) -> NormalizedDelayPerPacket {
717 self.build_truncated_with_rng()
718 }
719
720 /// Similar to [`build_truncated`](Self::build_truncated) but let you choose the random generator.
721 ///
722 /// See [`build`](Self::build) for details about the reason for using another random number generator than [`StdRng`].
723 pub fn build_truncated_with_rng<Rng: SeedableRng + RngCore>(
724 mut self,
725 ) -> NormalizedDelayPerPacket<Rng> {
726 let mean = self
727 .mean
728 .unwrap_or_else(|| Delay::from_millis(12))
729 .as_secs_f64();
730 let sigma = self.std_dev.unwrap_or(Delay::ZERO).as_secs_f64() / mean;
731 let lower = self.lower_bound.unwrap_or(Delay::ZERO).as_secs_f64() / mean;
732 let upper = self.upper_bound.map(|upper| upper.as_secs_f64() / mean);
733 let new_mean = mean * solve(1f64, sigma, Some(lower), upper).unwrap_or(1f64);
734 self.mean = Some(Delay::from_secs_f64(new_mean));
735 self.build_with_rng()
736 }
737}
738
739impl LogNormalizedDelayPerPacketConfig {
740 /// Creates an uninitialized config
741 pub fn new() -> Self {
742 Self {
743 mean: None,
744 std_dev: None,
745 upper_bound: None,
746 lower_bound: None,
747 count: 0,
748 seed: None,
749 }
750 }
751
752 /// Sets the mean
753 ///
754 /// If the mean is not set, 10ms will be used.
755 pub fn mean(mut self, mean: Delay) -> Self {
756 self.mean = Some(mean);
757 self
758 }
759
760 /// Sets the standard deviation
761 ///
762 /// If the standard deviation is not set, 0ms will be used.
763 pub fn std_dev(mut self, std_dev: Delay) -> Self {
764 self.std_dev = Some(std_dev);
765 self
766 }
767
768 /// Sets the upper bound
769 ///
770 /// If the upper bound is not set, the upper bound will be the one of [`Delay`].
771 pub fn upper_bound(mut self, upper_bound: Delay) -> Self {
772 self.upper_bound = Some(upper_bound);
773 self
774 }
775
776 /// Sets the lower bound
777 ///
778 /// If the lower bound is not set, 0ms will be used.
779 pub fn lower_bound(mut self, lower_bound: Delay) -> Self {
780 self.lower_bound = Some(lower_bound);
781 self
782 }
783
784 /// Sets the number of packets to repeat
785 ///
786 /// If the count is not set, it will be set to 0 (ie, infinite repeat).
787 pub fn count(mut self, count: usize) -> Self {
788 self.count = count;
789 self
790 }
791
792 /// Set the seed for a random generator
793 ///
794 /// If the seed is not set, `42` will be used.
795 pub fn seed(mut self, seed: u64) -> Self {
796 self.seed = Some(seed);
797 self
798 }
799
800 /// Allows to use a randomly generated seed
801 ///
802 /// This is equivalent to: `self.seed(rand::random())`
803 pub fn random_seed(mut self) -> Self {
804 self.seed = Some(rand::random());
805 self
806 }
807
808 /// Creates a new [`LogNormalizedDelayPerPacket`] corresponding to this config.
809 ///
810 /// The created model will use [`StdRng`] as source of randomness (the call is equivalent to `self.build_with_rng::<StdRng>()`).
811 /// It should be sufficient for most cases, but [`StdRng`] is not a portable random number generator,
812 /// so one may want to use a portable random number generator like [`ChaCha`](https://crates.io/crates/rand_chacha),
813 /// to this end one can use [`build_with_rng`](Self::build_with_rng).
814 pub fn build(self) -> LogNormalizedDelayPerPacket {
815 self.build_with_rng()
816 }
817
818 /// Creates a new [`LogNormalizedDelayPerPacket`] corresponding to this config.
819 ///
820 /// Unlike [`build`](Self::build), this method let you choose the random generator.
821 ///
822 /// # Example
823 /// ```rust
824 /// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
825 /// # use netem_trace::{Delay, DelayPerPacketTrace};
826 /// # use rand::rngs::StdRng;
827 /// # use rand_chacha::ChaCha20Rng;
828 ///
829 /// let log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
830 /// .mean(Delay::from_millis(12))
831 /// .std_dev(Delay::from_millis(1))
832 /// .count(3)
833 /// .seed(42);
834 ///
835 /// let mut default_build = log_normal_delay.clone().build();
836 /// let mut std_build = log_normal_delay.clone().build_with_rng::<StdRng>();
837 /// // ChaCha is deterministic and portable, unlike StdRng
838 /// let mut chacha_build = log_normal_delay.clone().build_with_rng::<ChaCha20Rng>();
839 ///
840 /// for cha in [12003077, 11716668, 11238761] {
841 /// let default = default_build.next_delay();
842 /// let std = std_build.next_delay();
843 /// let chacha = chacha_build.next_delay();
844 ///
845 /// assert!(default.is_some());
846 /// assert_eq!(default, std);
847 /// assert_ne!(default, chacha);
848 /// assert_eq!(chacha, Some(Delay::from_nanos(cha)));
849 /// }
850 ///
851 /// assert_eq!(default_build.next_delay(), None);
852 /// assert_eq!(std_build.next_delay(), None);
853 /// assert_eq!(chacha_build.next_delay(), None);
854 /// ```
855 pub fn build_with_rng<Rng: SeedableRng + RngCore>(self) -> LogNormalizedDelayPerPacket<Rng> {
856 let mean = self.mean.unwrap_or_else(|| Delay::from_millis(10));
857 let std_dev = self.std_dev.unwrap_or(Delay::ZERO);
858 let upper_bound = self.upper_bound;
859 let lower_bound = self.lower_bound.unwrap_or(Delay::ZERO);
860 let count = self.count;
861 let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
862 let rng = Rng::seed_from_u64(seed);
863 let delay_mean = mean.as_secs_f64();
864 let delay_std_dev = std_dev.as_secs_f64();
865
866 // Computing the mean and standard deviation of underlying normal Law
867 // Because Lognormal(μ , σ²) has a mean of exp(μ + σ²/2) and a standard deviation of sqrt((exp(σ²) - 1) exp(2μ + σ²))
868 // So we need to comput μ and σ, given the mean and standard deviation of the log-normal law
869 let normal_std_dev = f64::sqrt(f64::ln(
870 1.0 + (delay_std_dev.powi(2)) / (delay_mean.powi(2)),
871 ));
872 let normal_mean = f64::ln(delay_mean) - normal_std_dev.powi(2) / 2.;
873 let log_normal: LogNormal<f64> = LogNormal::new(normal_mean, normal_std_dev).unwrap();
874
875 LogNormalizedDelayPerPacket {
876 mean,
877 std_dev,
878 upper_bound,
879 lower_bound,
880 count,
881 current_count: 0,
882 seed,
883 rng,
884 log_normal,
885 }
886 }
887}
888
889macro_rules! impl_delay_per_packet_trace_config {
890 ($name:ident) => {
891 #[cfg_attr(feature = "serde", typetag::serde)]
892 impl DelayPerPacketTraceConfig for $name {
893 fn into_model(self: Box<$name>) -> Box<dyn DelayPerPacketTrace> {
894 Box::new(self.build())
895 }
896 }
897 };
898}
899
900impl_delay_per_packet_trace_config!(StaticDelayPerPacketConfig);
901impl_delay_per_packet_trace_config!(NormalizedDelayPerPacketConfig);
902impl_delay_per_packet_trace_config!(LogNormalizedDelayPerPacketConfig);
903impl_delay_per_packet_trace_config!(RepeatedDelayPerPacketPatternConfig);
904
905impl<Model: DelayPerPacketTrace + 'static> From<Model> for Box<dyn DelayPerPacketTrace> {
906 fn from(model: Model) -> Self {
907 Box::new(model)
908 }
909}
910
911/// Turn a [`DelayPerPacketTraceConfig`] into a forever repeated [`RepeatedDelayPerPacketPatternConfig`].
912pub trait Forever: DelayPerPacketTraceConfig {
913 fn forever(self) -> RepeatedDelayPerPacketPatternConfig;
914}
915
916/// Implement the [`Forever`] trait for the per-packet delay trace model config (any struct implements [`DelayPerPacketTraceConfig`]).
917#[macro_export]
918macro_rules! impl_forever_delay_per_packet {
919 ($name:ident) => {
920 impl Forever for $name {
921 fn forever(self) -> RepeatedDelayPerPacketPatternConfig {
922 RepeatedDelayPerPacketPatternConfig::new()
923 .pattern(vec![Box::new(self)])
924 .count(0)
925 }
926 }
927 };
928}
929
930impl_forever_delay_per_packet!(StaticDelayPerPacketConfig);
931impl_forever_delay_per_packet!(NormalizedDelayPerPacketConfig);
932
933impl Forever for RepeatedDelayPerPacketPatternConfig {
934 fn forever(self) -> RepeatedDelayPerPacketPatternConfig {
935 self.count(0)
936 }
937}
938
939#[cfg(test)]
940mod test {
941 use super::*;
942 use crate::model::StaticDelayPerPacketConfig;
943 use crate::DelayPerPacketTrace;
944
945 #[test]
946 fn test_static_delay_model() {
947 let mut static_delay = StaticDelayPerPacketConfig::new()
948 .delay(Delay::from_millis(10))
949 .count(1)
950 .build();
951 assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
952 assert_eq!(static_delay.next_delay(), None);
953 }
954
955 #[test]
956 #[cfg(feature = "serde")]
957 fn test_serde() {
958 let a = vec![
959 Box::new(
960 StaticDelayPerPacketConfig::new()
961 .delay(Delay::from_millis(10))
962 .count(1),
963 ) as Box<dyn DelayPerPacketTraceConfig>,
964 Box::new(
965 StaticDelayPerPacketConfig::new()
966 .delay(Delay::from_millis(20))
967 .count(1),
968 ) as Box<dyn DelayPerPacketTraceConfig>,
969 ];
970 let ser = Box::new(
971 RepeatedDelayPerPacketPatternConfig::new()
972 .pattern(a)
973 .count(2),
974 ) as Box<dyn DelayPerPacketTraceConfig>;
975 let ser_str = serde_json::to_string(&ser).unwrap();
976 #[cfg(feature = "human")]
977 let des_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
978 #[cfg(not(feature = "human"))]
979 let des_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
980 assert_eq!(ser_str, des_str);
981 let des: Box<dyn DelayPerPacketTraceConfig> = serde_json::from_str(des_str).unwrap();
982 let mut model = des.into_model();
983 assert_eq!(model.next_delay(), Some(Delay::from_millis(10)));
984 }
985}