fault_injector.rs 9.8 KB

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