fault_injector.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. use Error;
  2. use super::{DeviceLimits, Device};
  3. // We use our own RNG to stay compatible with #![no_std].
  4. // The use of the RNG below has a slight bias, but it doesn't matter.
  5. fn xorshift32(state: &mut u32) -> u32 {
  6. let mut x = *state;
  7. x ^= x << 13;
  8. x ^= x >> 17;
  9. x ^= x << 5;
  10. *state = x;
  11. x
  12. }
  13. fn check_rng(state: &mut u32, pct: u8) -> bool {
  14. xorshift32(state) % 100 < pct as u32
  15. }
  16. fn corrupt<T: AsMut<[u8]>>(state: &mut u32, mut buffer: T) {
  17. let mut buffer = buffer.as_mut();
  18. // We introduce a single bitflip, as the most likely, and the hardest to detect, error.
  19. let index = (xorshift32(state) as usize) % buffer.len();
  20. let bit = 1 << (xorshift32(state) % 8) as u8;
  21. buffer[index] ^= bit;
  22. }
  23. // This could be fixed once associated consts are stable.
  24. const MTU: usize = 1536;
  25. #[derive(Debug, Clone, Copy)]
  26. struct Config {
  27. corrupt_pct: u8,
  28. drop_pct: u8,
  29. reorder_pct: u8
  30. }
  31. /// A fault injector device.
  32. ///
  33. /// A fault injector is a device that randomly drops or corrupts packets traversing it,
  34. /// according to preset probabilities.
  35. #[derive(Debug)]
  36. pub struct FaultInjector<T: Device> {
  37. lower: T,
  38. state: u32,
  39. config: Config
  40. }
  41. impl<T: Device> FaultInjector<T> {
  42. /// Create a tracer device, using the given random number generator seed.
  43. pub fn new(lower: T, seed: u32) -> FaultInjector<T> {
  44. FaultInjector {
  45. lower: lower,
  46. state: seed,
  47. config: Config {
  48. corrupt_pct: 0,
  49. drop_pct: 0,
  50. reorder_pct: 0
  51. }
  52. }
  53. }
  54. /// Return the underlying device, consuming the tracer.
  55. pub fn into_lower(self) -> T {
  56. self.lower
  57. }
  58. /// Return the probability of corrupting a packet, in percents.
  59. pub fn corrupt_chance(&self) -> u8 {
  60. self.config.corrupt_pct
  61. }
  62. /// Return the probability of dropping a packet, in percents.
  63. pub fn drop_chance(&self) -> u8 {
  64. self.config.drop_pct
  65. }
  66. /// Set the probability of corrupting a packet, in percents.
  67. ///
  68. /// # Panics
  69. /// This function panics if the probability is not between 0% and 100%.
  70. pub fn set_corrupt_chance(&mut self, pct: u8) {
  71. if pct > 100 { panic!("percentage out of range") }
  72. self.config.corrupt_pct = pct
  73. }
  74. /// Set the probability of dropping a packet, in percents.
  75. ///
  76. /// # Panics
  77. /// This function panics if the probability is not between 0% and 100%.
  78. pub fn set_drop_chance(&mut self, pct: u8) {
  79. if pct > 100 { panic!("percentage out of range") }
  80. self.config.drop_pct = pct
  81. }
  82. }
  83. impl<T: Device> Device for FaultInjector<T>
  84. where T::RxBuffer: AsMut<[u8]> {
  85. type RxBuffer = T::RxBuffer;
  86. type TxBuffer = TxBuffer<T::TxBuffer>;
  87. fn limits(&self) -> DeviceLimits {
  88. let mut limits = self.lower.limits();
  89. if limits.max_transmission_unit > MTU {
  90. limits.max_transmission_unit = MTU;
  91. }
  92. limits
  93. }
  94. fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
  95. let mut buffer = try!(self.lower.receive());
  96. if check_rng(&mut self.state, self.config.drop_pct) {
  97. net_trace!("rx: dropping a packet");
  98. return Err(Error::Exhausted)
  99. }
  100. if check_rng(&mut self.state, self.config.corrupt_pct) {
  101. net_trace!("rx: corrupting a packet");
  102. corrupt(&mut self.state, &mut buffer)
  103. }
  104. Ok(buffer)
  105. }
  106. fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
  107. let buffer;
  108. if check_rng(&mut self.state, self.config.drop_pct) {
  109. net_trace!("tx: dropping a packet");
  110. buffer = None;
  111. } else {
  112. buffer = Some(try!(self.lower.transmit(length)));
  113. }
  114. Ok(TxBuffer {
  115. buffer: buffer,
  116. state: xorshift32(&mut self.state),
  117. config: self.config,
  118. junk: [0; MTU],
  119. length: length
  120. })
  121. }
  122. }
  123. #[doc(hidden)]
  124. pub struct TxBuffer<T: AsRef<[u8]> + AsMut<[u8]>> {
  125. state: u32,
  126. config: Config,
  127. buffer: Option<T>,
  128. junk: [u8; MTU],
  129. length: usize
  130. }
  131. impl<T: AsRef<[u8]> + AsMut<[u8]>> AsRef<[u8]>
  132. for TxBuffer<T> {
  133. fn as_ref(&self) -> &[u8] {
  134. match self.buffer {
  135. Some(ref buf) => buf.as_ref(),
  136. None => &self.junk[..self.length]
  137. }
  138. }
  139. }
  140. impl<T: AsRef<[u8]> + AsMut<[u8]>> AsMut<[u8]>
  141. for TxBuffer<T> {
  142. fn as_mut(&mut self) -> &mut [u8] {
  143. match self.buffer {
  144. Some(ref mut buf) => buf.as_mut(),
  145. None => &mut self.junk[..self.length]
  146. }
  147. }
  148. }
  149. impl<T: AsRef<[u8]> + AsMut<[u8]>> Drop for TxBuffer<T> {
  150. fn drop(&mut self) {
  151. match self.buffer {
  152. Some(ref mut buf) => {
  153. if check_rng(&mut self.state, self.config.corrupt_pct) {
  154. net_trace!("tx: corrupting a packet");
  155. corrupt(&mut self.state, buf)
  156. }
  157. },
  158. None => ()
  159. }
  160. }
  161. }