fault_injector.rs 9.2 KB

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