|
@@ -1,8 +1,5 @@
|
|
|
-use core::cell::RefCell;
|
|
|
-
|
|
|
use crate::phy::{self, Device, DeviceCapabilities};
|
|
|
use crate::time::{Duration, Instant};
|
|
|
-use crate::{Error, Result};
|
|
|
|
|
|
// We use our own RNG to stay compatible with #![no_std].
|
|
|
// The use of the RNG below has a slight bias, but it doesn't matter.
|
|
@@ -96,23 +93,24 @@ impl State {
|
|
|
#[derive(Debug)]
|
|
|
pub struct FaultInjector<D: Device> {
|
|
|
inner: D,
|
|
|
- state: RefCell<State>,
|
|
|
+ state: State,
|
|
|
config: Config,
|
|
|
+ rx_buf: [u8; MTU],
|
|
|
}
|
|
|
|
|
|
impl<D: Device> FaultInjector<D> {
|
|
|
/// Create a fault injector device, using the given random number generator seed.
|
|
|
pub fn new(inner: D, seed: u32) -> FaultInjector<D> {
|
|
|
- let state = State {
|
|
|
- rng_seed: seed,
|
|
|
- refilled_at: Instant::from_millis(0),
|
|
|
- tx_bucket: 0,
|
|
|
- rx_bucket: 0,
|
|
|
- };
|
|
|
FaultInjector {
|
|
|
inner,
|
|
|
- state: RefCell::new(state),
|
|
|
+ state: State {
|
|
|
+ rng_seed: seed,
|
|
|
+ refilled_at: Instant::from_millis(0),
|
|
|
+ tx_bucket: 0,
|
|
|
+ rx_bucket: 0,
|
|
|
+ },
|
|
|
config: Config::default(),
|
|
|
+ rx_buf: [0u8; MTU],
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -190,13 +188,13 @@ impl<D: Device> FaultInjector<D> {
|
|
|
|
|
|
/// Set the interval for packet rate limiting, in milliseconds.
|
|
|
pub fn set_bucket_interval(&mut self, interval: Duration) {
|
|
|
- self.state.borrow_mut().refilled_at = Instant::from_millis(0);
|
|
|
+ self.state.refilled_at = Instant::from_millis(0);
|
|
|
self.config.interval = interval
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl<D: Device> Device for FaultInjector<D> {
|
|
|
- type RxToken<'a> = RxToken<'a, D::RxToken<'a>>
|
|
|
+ type RxToken<'a> = RxToken<'a>
|
|
|
where
|
|
|
Self: 'a;
|
|
|
type TxToken<'a> = TxToken<'a, D::TxToken<'a>>
|
|
@@ -211,117 +209,94 @@ impl<D: Device> Device for FaultInjector<D> {
|
|
|
caps
|
|
|
}
|
|
|
|
|
|
- fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
|
|
- let &mut Self {
|
|
|
- ref mut inner,
|
|
|
- ref state,
|
|
|
- config,
|
|
|
- } = self;
|
|
|
- inner.receive().map(|(rx_token, tx_token)| {
|
|
|
- let rx = RxToken {
|
|
|
- state,
|
|
|
- config,
|
|
|
- token: rx_token,
|
|
|
- corrupt: [0; MTU],
|
|
|
- };
|
|
|
- let tx = TxToken {
|
|
|
- state,
|
|
|
- config,
|
|
|
- token: tx_token,
|
|
|
- junk: [0; MTU],
|
|
|
- };
|
|
|
- (rx, tx)
|
|
|
- })
|
|
|
+ fn receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
|
|
+ let (rx_token, tx_token) = self.inner.receive(timestamp)?;
|
|
|
+
|
|
|
+ let len = super::RxToken::consume(rx_token, |buffer| {
|
|
|
+ if (self.config.max_size > 0 && buffer.len() > self.config.max_size)
|
|
|
+ || buffer.len() > self.rx_buf.len()
|
|
|
+ {
|
|
|
+ net_trace!("rx: dropping a packet that is too large");
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+ self.rx_buf[..buffer.len()].copy_from_slice(buffer);
|
|
|
+ Some(buffer.len())
|
|
|
+ })?;
|
|
|
+
|
|
|
+ let buf = &mut self.rx_buf[..len];
|
|
|
+
|
|
|
+ if self.state.maybe(self.config.drop_pct) {
|
|
|
+ net_trace!("rx: randomly dropping a packet");
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+
|
|
|
+ if !self.state.maybe_receive(&self.config, timestamp) {
|
|
|
+ net_trace!("rx: dropping a packet because of rate limiting");
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.state.maybe(self.config.corrupt_pct) {
|
|
|
+ net_trace!("rx: randomly corrupting a packet");
|
|
|
+ self.state.corrupt(&mut buf[..]);
|
|
|
+ }
|
|
|
+
|
|
|
+ let rx = RxToken { buf };
|
|
|
+ let tx = TxToken {
|
|
|
+ state: &mut self.state,
|
|
|
+ config: self.config,
|
|
|
+ token: tx_token,
|
|
|
+ junk: [0; MTU],
|
|
|
+ timestamp,
|
|
|
+ };
|
|
|
+ Some((rx, tx))
|
|
|
}
|
|
|
|
|
|
- fn transmit(&mut self) -> Option<Self::TxToken<'_>> {
|
|
|
- let &mut Self {
|
|
|
- ref mut inner,
|
|
|
- ref state,
|
|
|
- config,
|
|
|
- } = self;
|
|
|
- inner.transmit().map(|token| TxToken {
|
|
|
- state,
|
|
|
- config,
|
|
|
+ fn transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>> {
|
|
|
+ self.inner.transmit(timestamp).map(|token| TxToken {
|
|
|
+ state: &mut self.state,
|
|
|
+ config: self.config,
|
|
|
token,
|
|
|
junk: [0; MTU],
|
|
|
+ timestamp,
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
-pub struct RxToken<'a, Rx: phy::RxToken> {
|
|
|
- state: &'a RefCell<State>,
|
|
|
- config: Config,
|
|
|
- token: Rx,
|
|
|
- corrupt: [u8; MTU],
|
|
|
+pub struct RxToken<'a> {
|
|
|
+ buf: &'a mut [u8],
|
|
|
}
|
|
|
|
|
|
-impl<'a, Rx: phy::RxToken> phy::RxToken for RxToken<'a, Rx> {
|
|
|
- fn consume<R, F>(self, timestamp: Instant, f: F) -> Result<R>
|
|
|
+impl<'a> phy::RxToken for RxToken<'a> {
|
|
|
+ fn consume<R, F>(self, f: F) -> R
|
|
|
where
|
|
|
- F: FnOnce(&mut [u8]) -> Result<R>,
|
|
|
+ F: FnOnce(&mut [u8]) -> R,
|
|
|
{
|
|
|
- if self.state.borrow_mut().maybe(self.config.drop_pct) {
|
|
|
- net_trace!("rx: randomly dropping a packet");
|
|
|
- return Err(Error::Exhausted);
|
|
|
- }
|
|
|
- if !self
|
|
|
- .state
|
|
|
- .borrow_mut()
|
|
|
- .maybe_receive(&self.config, timestamp)
|
|
|
- {
|
|
|
- net_trace!("rx: dropping a packet because of rate limiting");
|
|
|
- return Err(Error::Exhausted);
|
|
|
- }
|
|
|
- let Self {
|
|
|
- token,
|
|
|
- config,
|
|
|
- state,
|
|
|
- mut corrupt,
|
|
|
- } = self;
|
|
|
- token.consume(timestamp, |buffer| {
|
|
|
- if config.max_size > 0 && buffer.as_ref().len() > config.max_size {
|
|
|
- net_trace!("rx: dropping a packet that is too large");
|
|
|
- return Err(Error::Exhausted);
|
|
|
- }
|
|
|
- if state.borrow_mut().maybe(config.corrupt_pct) {
|
|
|
- net_trace!("rx: randomly corrupting a packet");
|
|
|
- let mut corrupt = &mut corrupt[..buffer.len()];
|
|
|
- corrupt.copy_from_slice(buffer);
|
|
|
- state.borrow_mut().corrupt(&mut corrupt);
|
|
|
- f(corrupt)
|
|
|
- } else {
|
|
|
- f(buffer)
|
|
|
- }
|
|
|
- })
|
|
|
+ f(self.buf)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
pub struct TxToken<'a, Tx: phy::TxToken> {
|
|
|
- state: &'a RefCell<State>,
|
|
|
+ state: &'a mut State,
|
|
|
config: Config,
|
|
|
token: Tx,
|
|
|
junk: [u8; MTU],
|
|
|
+ timestamp: Instant,
|
|
|
}
|
|
|
|
|
|
impl<'a, Tx: phy::TxToken> phy::TxToken for TxToken<'a, Tx> {
|
|
|
- fn consume<R, F>(mut self, timestamp: Instant, len: usize, f: F) -> Result<R>
|
|
|
+ fn consume<R, F>(mut self, len: usize, f: F) -> R
|
|
|
where
|
|
|
- F: FnOnce(&mut [u8]) -> Result<R>,
|
|
|
+ F: FnOnce(&mut [u8]) -> R,
|
|
|
{
|
|
|
- let drop = if self.state.borrow_mut().maybe(self.config.drop_pct) {
|
|
|
+ let drop = if self.state.maybe(self.config.drop_pct) {
|
|
|
net_trace!("tx: randomly dropping a packet");
|
|
|
true
|
|
|
} else if self.config.max_size > 0 && len > self.config.max_size {
|
|
|
net_trace!("tx: dropping a packet that is too large");
|
|
|
true
|
|
|
- } else if !self
|
|
|
- .state
|
|
|
- .borrow_mut()
|
|
|
- .maybe_transmit(&self.config, timestamp)
|
|
|
- {
|
|
|
+ } else if !self.state.maybe_transmit(&self.config, self.timestamp) {
|
|
|
net_trace!("tx: dropping a packet because of rate limiting");
|
|
|
true
|
|
|
} else {
|
|
@@ -332,16 +307,10 @@ impl<'a, Tx: phy::TxToken> phy::TxToken for TxToken<'a, Tx> {
|
|
|
return f(&mut self.junk[..len]);
|
|
|
}
|
|
|
|
|
|
- let Self {
|
|
|
- token,
|
|
|
- state,
|
|
|
- config,
|
|
|
- ..
|
|
|
- } = self;
|
|
|
- token.consume(timestamp, len, |mut buf| {
|
|
|
- if state.borrow_mut().maybe(config.corrupt_pct) {
|
|
|
+ self.token.consume(len, |mut buf| {
|
|
|
+ if self.state.maybe(self.config.corrupt_pct) {
|
|
|
net_trace!("tx: corrupting a packet");
|
|
|
- state.borrow_mut().corrupt(&mut buf)
|
|
|
+ self.state.corrupt(&mut buf)
|
|
|
}
|
|
|
f(buf)
|
|
|
})
|