fault_injector.rs 9.2 KB

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