fault_injector.rs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. use std::time::{Instant, Duration};
  2. use Error;
  3. use super::{DeviceLimits, Device};
  4. // We use our own RNG to stay compatible with #![no_std].
  5. // The use of the RNG below has a slight bias, but it doesn't matter.
  6. fn xorshift32(state: &mut u32) -> u32 {
  7. let mut x = *state;
  8. x ^= x << 13;
  9. x ^= x >> 17;
  10. x ^= x << 5;
  11. *state = x;
  12. x
  13. }
  14. // This could be fixed once associated consts are stable.
  15. const MTU: usize = 1536;
  16. #[derive(Debug, Clone, Copy, Default)]
  17. struct Config {
  18. corrupt_pct: u8,
  19. drop_pct: u8,
  20. reorder_pct: u8,
  21. max_size: usize,
  22. max_tx_rate: u64,
  23. max_rx_rate: u64,
  24. interval: Duration,
  25. }
  26. #[derive(Debug, Clone, Copy)]
  27. struct State {
  28. rng_seed: u32,
  29. refilled_at: Instant,
  30. tx_bucket: u64,
  31. rx_bucket: u64,
  32. }
  33. impl State {
  34. fn maybe(&mut self, pct: u8) -> bool {
  35. xorshift32(&mut self.rng_seed) % 100 < pct as u32
  36. }
  37. fn corrupt<T: AsMut<[u8]>>(&mut self, mut buffer: T) {
  38. let mut buffer = buffer.as_mut();
  39. // We introduce a single bitflip, as the most likely, and the hardest to detect, error.
  40. let index = (xorshift32(&mut self.rng_seed) as usize) % buffer.len();
  41. let bit = 1 << (xorshift32(&mut self.rng_seed) % 8) as u8;
  42. buffer[index] ^= bit;
  43. }
  44. fn refill(&mut self, config: &Config) {
  45. if self.refilled_at.elapsed() > config.interval {
  46. self.tx_bucket = config.max_tx_rate;
  47. self.rx_bucket = config.max_rx_rate;
  48. self.refilled_at = Instant::now();
  49. }
  50. }
  51. fn maybe_transmit(&mut self, config: &Config) -> bool {
  52. if config.max_tx_rate == 0 { return true }
  53. self.refill(config);
  54. if self.tx_bucket > 0 {
  55. self.tx_bucket -= 1;
  56. true
  57. } else {
  58. false
  59. }
  60. }
  61. fn maybe_receive(&mut self, config: &Config) -> bool {
  62. if config.max_rx_rate == 0 { return true }
  63. self.refill(config);
  64. if self.rx_bucket > 0 {
  65. self.rx_bucket -= 1;
  66. true
  67. } else {
  68. false
  69. }
  70. }
  71. }
  72. /// A fault injector device.
  73. ///
  74. /// A fault injector is a device that alters packets traversing through it to simulate
  75. /// adverse network conditions (such as random packet loss or corruption), or software
  76. /// or hardware limitations (such as a limited number or size of usable network buffers).
  77. #[derive(Debug)]
  78. pub struct FaultInjector<T: Device> {
  79. lower: T,
  80. state: State,
  81. config: Config
  82. }
  83. impl<T: Device> FaultInjector<T> {
  84. /// Create a fault injector device, using the given random number generator seed.
  85. pub fn new(lower: T, seed: u32) -> FaultInjector<T> {
  86. FaultInjector {
  87. lower: lower,
  88. state: State {
  89. rng_seed: seed,
  90. refilled_at: Instant::now(),
  91. tx_bucket: 0,
  92. rx_bucket: 0,
  93. },
  94. config: Config::default()
  95. }
  96. }
  97. /// Return the underlying device, consuming the fault injector.
  98. pub fn into_lower(self) -> T {
  99. self.lower
  100. }
  101. /// Return the probability of corrupting a packet, in percents.
  102. pub fn corrupt_chance(&self) -> u8 {
  103. self.config.corrupt_pct
  104. }
  105. /// Return the probability of dropping a packet, in percents.
  106. pub fn drop_chance(&self) -> u8 {
  107. self.config.drop_pct
  108. }
  109. /// Return the maximum packet size, in octets.
  110. pub fn max_packet_size(&self) -> usize {
  111. self.config.max_size
  112. }
  113. /// Return the maximum packet transmission rate, in packets per second.
  114. pub fn max_tx_rate(&self) -> u64 {
  115. self.config.max_rx_rate
  116. }
  117. /// Return the maximum packet reception rate, in packets per second.
  118. pub fn max_rx_rate(&self) -> u64 {
  119. self.config.max_tx_rate
  120. }
  121. /// Return the interval for packet rate limiting, in milliseconds.
  122. pub fn bucket_interval(&self) -> Duration {
  123. self.config.interval
  124. }
  125. /// Set the probability of corrupting a packet, in percents.
  126. ///
  127. /// # Panics
  128. /// This function panics if the probability is not between 0% and 100%.
  129. pub fn set_corrupt_chance(&mut self, pct: u8) {
  130. if pct > 100 { panic!("percentage out of range") }
  131. self.config.corrupt_pct = pct
  132. }
  133. /// Set the probability of dropping a packet, in percents.
  134. ///
  135. /// # Panics
  136. /// This function panics if the probability is not between 0% and 100%.
  137. pub fn set_drop_chance(&mut self, pct: u8) {
  138. if pct > 100 { panic!("percentage out of range") }
  139. self.config.drop_pct = pct
  140. }
  141. /// Set the maximum packet size, in octets.
  142. pub fn set_max_packet_size(&mut self, size: usize) {
  143. self.config.max_size = size
  144. }
  145. /// Set the maximum packet transmission rate, in packets per interval.
  146. pub fn set_max_tx_rate(&mut self, rate: u64) {
  147. self.config.max_tx_rate = rate
  148. }
  149. /// Set the maximum packet reception rate, in packets per interval.
  150. pub fn set_max_rx_rate(&mut self, rate: u64) {
  151. self.config.max_rx_rate = rate
  152. }
  153. /// Set the interval for packet rate limiting, in milliseconds.
  154. pub fn set_bucket_interval(&mut self, interval: Duration) {
  155. self.state.refilled_at = Instant::now() - self.config.interval;
  156. self.config.interval = interval
  157. }
  158. }
  159. impl<T: Device> Device for FaultInjector<T>
  160. where T::RxBuffer: AsMut<[u8]> {
  161. type RxBuffer = T::RxBuffer;
  162. type TxBuffer = TxBuffer<T::TxBuffer>;
  163. fn limits(&self) -> DeviceLimits {
  164. let mut limits = self.lower.limits();
  165. if limits.max_transmission_unit > MTU {
  166. limits.max_transmission_unit = MTU;
  167. }
  168. limits
  169. }
  170. fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
  171. let mut buffer = try!(self.lower.receive());
  172. if self.state.maybe(self.config.drop_pct) {
  173. net_trace!("rx: randomly dropping a packet");
  174. return Err(Error::Exhausted)
  175. }
  176. if self.state.maybe(self.config.corrupt_pct) {
  177. net_trace!("rx: randomly corrupting a packet");
  178. self.state.corrupt(&mut buffer)
  179. }
  180. if self.config.max_size > 0 && buffer.as_ref().len() > self.config.max_size {
  181. net_trace!("rx: dropping a packet that is too large");
  182. return Err(Error::Exhausted)
  183. }
  184. if !self.state.maybe_receive(&self.config) {
  185. net_trace!("rx: dropping a packet because of rate limiting");
  186. return Err(Error::Exhausted)
  187. }
  188. Ok(buffer)
  189. }
  190. fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
  191. let buffer;
  192. if self.state.maybe(self.config.drop_pct) {
  193. net_trace!("tx: randomly dropping a packet");
  194. buffer = None;
  195. } else if self.config.max_size > 0 && length > self.config.max_size {
  196. net_trace!("tx: dropping a packet that is too large");
  197. buffer = None;
  198. } else if !self.state.maybe_transmit(&self.config) {
  199. net_trace!("tx: dropping a packet because of rate limiting");
  200. buffer = None;
  201. } else {
  202. buffer = Some(try!(self.lower.transmit(length)));
  203. }
  204. Ok(TxBuffer {
  205. buffer: buffer,
  206. state: self.state.clone(),
  207. config: self.config,
  208. junk: [0; MTU],
  209. length: length
  210. })
  211. }
  212. }
  213. #[doc(hidden)]
  214. pub struct TxBuffer<T: AsRef<[u8]> + AsMut<[u8]>> {
  215. state: State,
  216. config: Config,
  217. buffer: Option<T>,
  218. junk: [u8; MTU],
  219. length: usize
  220. }
  221. impl<T: AsRef<[u8]> + AsMut<[u8]>> AsRef<[u8]>
  222. for TxBuffer<T> {
  223. fn as_ref(&self) -> &[u8] {
  224. match self.buffer {
  225. Some(ref buf) => buf.as_ref(),
  226. None => &self.junk[..self.length]
  227. }
  228. }
  229. }
  230. impl<T: AsRef<[u8]> + AsMut<[u8]>> AsMut<[u8]>
  231. for TxBuffer<T> {
  232. fn as_mut(&mut self) -> &mut [u8] {
  233. match self.buffer {
  234. Some(ref mut buf) => buf.as_mut(),
  235. None => &mut self.junk[..self.length]
  236. }
  237. }
  238. }
  239. impl<T: AsRef<[u8]> + AsMut<[u8]>> Drop for TxBuffer<T> {
  240. fn drop(&mut self) {
  241. match self.buffer {
  242. Some(ref mut buf) => {
  243. if self.state.maybe(self.config.corrupt_pct) {
  244. net_trace!("tx: corrupting a packet");
  245. self.state.corrupt(buf)
  246. }
  247. },
  248. None => ()
  249. }
  250. }
  251. }