fault_injector.rs 9.4 KB

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