Inject the current timestamp into Device::{transmit,receive}.
Various parts of smoltcp require an arrow of time; a monotonically increasing timestamp. Most obviously this is TCP sockets, but the tracer and the pcap writer devices also benefit from having timestamps. There are a few ways this could be implemented: 1. using a static Cell, global for the entire smoltcp crate; 2. using a static method on Device; 3. using an instance method on Device; 4. passing the current timestamp into *Interface::poll. The first two options are undesirable because they create a notion of global clock, and interfere e.g. with mocking. The third option is undesirable because not all devices are inherently tied to a particular clock, e.g. a loopback device isn't. Therefore, the timestamp is injected into both sockets and devices through the *Interface::poll method.v0.7.x
parent
fe6fb087e5
commit
b97cacd521
|
@ -77,7 +77,7 @@ fn main() {
|
|||
}
|
||||
|
||||
let mut device = Loopback::new();
|
||||
let mut device = EthernetTracer::new(device, |printer| trace!("{}", printer));
|
||||
let mut device = EthernetTracer::new(device, |printer, _timestamp| trace!("{}", printer));
|
||||
|
||||
let mut arp_cache_entries: [_; 8] = Default::default();
|
||||
let mut arp_cache = SliceArpCache::new(&mut arp_cache_entries[..]);
|
||||
|
|
|
@ -8,7 +8,7 @@ fn main() {
|
|||
let ifname = env::args().nth(1).unwrap();
|
||||
let mut socket = RawSocket::new(ifname.as_ref()).unwrap();
|
||||
loop {
|
||||
let buffer = socket.receive().unwrap();
|
||||
let buffer = socket.receive(/*timestamp=*/0).unwrap();
|
||||
print!("{}", PrettyPrinter::<EthernetFrame<&[u8]>>::new("", &buffer))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ pub fn setup_device(more_args: &[&str])
|
|||
let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().subsec_nanos();
|
||||
|
||||
let device = TapInterface::new(&matches.free[0]).unwrap();
|
||||
let device = EthernetTracer::new(device, |printer| trace!("{}", printer));
|
||||
let device = EthernetTracer::new(device, |printer, _timestamp| trace!("{}", printer));
|
||||
let mut device = FaultInjector::new(device, seed);
|
||||
device.set_drop_chance(drop_chance);
|
||||
device.set_corrupt_chance(corrupt_chance);
|
||||
|
|
|
@ -116,7 +116,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||
}
|
||||
|
||||
// Now, receive any incoming packets.
|
||||
let rx_buffer = self.device.receive()?;
|
||||
let rx_buffer = self.device.receive(timestamp)?;
|
||||
let eth_frame = EthernetFrame::new_checked(&rx_buffer)?;
|
||||
|
||||
// Ignore any packets not directed to our hardware address.
|
||||
|
@ -134,7 +134,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||
_ => return Err(Error::Unrecognized),
|
||||
};
|
||||
|
||||
self.send_response(response)
|
||||
self.send_response(timestamp, response)
|
||||
}
|
||||
|
||||
// Snoop all ARP traffic, and respond to ARP packets directed at us.
|
||||
|
@ -360,7 +360,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||
Ok(Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr))
|
||||
}
|
||||
|
||||
fn send_response(&mut self, response: Response) -> Result<(), Error> {
|
||||
fn send_response(&mut self, timestamp: u64, response: Response) -> Result<(), Error> {
|
||||
macro_rules! ip_response {
|
||||
($tx_buffer:ident, $frame:ident, $ip_repr:ident) => ({
|
||||
let dst_hardware_addr =
|
||||
|
@ -371,7 +371,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||
|
||||
let frame_len = EthernetFrame::<&[u8]>::buffer_len($ip_repr.buffer_len() +
|
||||
$ip_repr.payload_len);
|
||||
$tx_buffer = self.device.transmit(frame_len)?;
|
||||
$tx_buffer = self.device.transmit(timestamp, frame_len)?;
|
||||
$frame = EthernetFrame::new_checked(&mut $tx_buffer)
|
||||
.expect("transmit frame too small");
|
||||
$frame.set_src_addr(self.hardware_addr);
|
||||
|
@ -387,7 +387,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||
match response {
|
||||
Response::Arp(repr) => {
|
||||
let tx_len = EthernetFrame::<&[u8]>::buffer_len(repr.buffer_len());
|
||||
let mut tx_buffer = self.device.transmit(tx_len)?;
|
||||
let mut tx_buffer = self.device.transmit(timestamp, tx_len)?;
|
||||
let mut frame = EthernetFrame::new_checked(&mut tx_buffer)
|
||||
.expect("transmit frame too small");
|
||||
frame.set_src_addr(self.hardware_addr);
|
||||
|
@ -449,7 +449,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||
Some(dst_hardware_addr) => {
|
||||
let tx_len = EthernetFrame::<&[u8]>::buffer_len(repr.buffer_len() +
|
||||
payload.buffer_len());
|
||||
let mut tx_buffer = device.transmit(tx_len)?;
|
||||
let mut tx_buffer = device.transmit(timestamp, tx_len)?;
|
||||
let mut frame = EthernetFrame::new_checked(&mut tx_buffer)
|
||||
.expect("transmit frame too small");
|
||||
frame.set_src_addr(src_hardware_addr);
|
||||
|
@ -480,7 +480,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||
};
|
||||
|
||||
let tx_len = EthernetFrame::<&[u8]>::buffer_len(payload.buffer_len());
|
||||
let mut tx_buffer = device.transmit(tx_len)?;
|
||||
let mut tx_buffer = device.transmit(timestamp, tx_len)?;
|
||||
let mut frame = EthernetFrame::new_checked(&mut tx_buffer)
|
||||
.expect("transmit frame too small");
|
||||
frame.set_src_addr(src_hardware_addr);
|
||||
|
|
|
@ -229,8 +229,8 @@ impl<T: Device> Device for FaultInjector<T>
|
|||
limits
|
||||
}
|
||||
|
||||
fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
|
||||
let mut buffer = self.lower.receive()?;
|
||||
fn receive(&mut self, timestamp: u64) -> Result<Self::RxBuffer, Error> {
|
||||
let mut buffer = self.lower.receive(timestamp)?;
|
||||
if self.state.maybe(self.config.drop_pct) {
|
||||
net_trace!("rx: randomly dropping a packet");
|
||||
return Err(Error::Exhausted)
|
||||
|
@ -250,7 +250,7 @@ impl<T: Device> Device for FaultInjector<T>
|
|||
Ok(buffer)
|
||||
}
|
||||
|
||||
fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
fn transmit(&mut self, timestamp: u64, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
let buffer;
|
||||
if self.state.maybe(self.config.drop_pct) {
|
||||
net_trace!("tx: randomly dropping a packet");
|
||||
|
@ -262,7 +262,7 @@ impl<T: Device> Device for FaultInjector<T>
|
|||
net_trace!("tx: dropping a packet because of rate limiting");
|
||||
buffer = None;
|
||||
} else {
|
||||
buffer = Some(self.lower.transmit(length)?);
|
||||
buffer = Some(self.lower.transmit(timestamp, length)?);
|
||||
}
|
||||
Ok(TxBuffer {
|
||||
buffer: buffer,
|
||||
|
|
|
@ -39,14 +39,14 @@ impl Device for Loopback {
|
|||
}
|
||||
}
|
||||
|
||||
fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
|
||||
fn receive(&mut self, _timestamp: u64) -> Result<Self::RxBuffer, Error> {
|
||||
match self.0.borrow_mut().pop_front() {
|
||||
Some(packet) => Ok(packet),
|
||||
None => Err(Error::Exhausted)
|
||||
}
|
||||
}
|
||||
|
||||
fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
fn transmit(&mut self, _timestamp: u64, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
let mut buffer = Vec::new();
|
||||
buffer.resize(length, 0);
|
||||
Ok(TxBuffer {
|
||||
|
|
|
@ -61,7 +61,7 @@ impl Device for EthernetDevice {
|
|||
limits
|
||||
}
|
||||
|
||||
fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
|
||||
fn receive(&mut self, _timestamp: u64) -> Result<Self::RxBuffer, Error> {
|
||||
if rx_full() {
|
||||
let index = self.rx_next;
|
||||
self.rx_next = (self.rx_next + 1) % RX_BUFFERS.len();
|
||||
|
@ -75,7 +75,7 @@ impl Device for EthernetDevice {
|
|||
}
|
||||
}
|
||||
|
||||
fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
fn transmit(&mut self, _timestamp: u64, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
if tx_empty() {
|
||||
let index = self.tx_next;
|
||||
self.tx_next = (self.tx_next + 1) % TX_BUFFERS.len();
|
||||
|
@ -175,12 +175,12 @@ pub trait Device {
|
|||
/// It is expected that a `receive` implementation, once a packet is written to memory
|
||||
/// through DMA, would gain ownership of the underlying buffer, provide it for parsing,
|
||||
/// and return it to the network device once it is dropped.
|
||||
fn receive(&mut self) -> Result<Self::RxBuffer, Error>;
|
||||
fn receive(&mut self, timestamp: u64) -> Result<Self::RxBuffer, Error>;
|
||||
|
||||
/// Transmit a frame.
|
||||
///
|
||||
/// It is expected that a `transmit` implementation would gain ownership of a buffer with
|
||||
/// the requested length, provide it for emission, and schedule it to be read from
|
||||
/// memory by the network device once it is dropped.
|
||||
fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error>;
|
||||
fn transmit(&mut self, timestamp: u64, length: usize) -> Result<Self::TxBuffer, Error>;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ impl Device for RawSocket {
|
|||
}
|
||||
}
|
||||
|
||||
fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
|
||||
fn receive(&mut self, _timestamp: u64) -> Result<Self::RxBuffer, Error> {
|
||||
let mut lower = self.lower.borrow_mut();
|
||||
let mut buffer = vec![0; self.mtu];
|
||||
let size = lower.recv(&mut buffer[..]).unwrap();
|
||||
|
@ -48,7 +48,7 @@ impl Device for RawSocket {
|
|||
Ok(buffer)
|
||||
}
|
||||
|
||||
fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
fn transmit(&mut self, _timestamp: u64, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
Ok(TxBuffer {
|
||||
lower: self.lower.clone(),
|
||||
buffer: vec![0; length]
|
||||
|
|
|
@ -41,7 +41,7 @@ impl Device for TapInterface {
|
|||
}
|
||||
}
|
||||
|
||||
fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
|
||||
fn receive(&mut self, _timestamp: u64) -> Result<Self::RxBuffer, Error> {
|
||||
let mut lower = self.lower.borrow_mut();
|
||||
let mut buffer = vec![0; self.mtu];
|
||||
match lower.recv(&mut buffer[..]) {
|
||||
|
@ -56,7 +56,7 @@ impl Device for TapInterface {
|
|||
}
|
||||
}
|
||||
|
||||
fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
fn transmit(&mut self, _timestamp: u64, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
Ok(TxBuffer {
|
||||
lower: self.lower.clone(),
|
||||
buffer: vec![0; length]
|
||||
|
|
|
@ -8,26 +8,13 @@ use super::{DeviceLimits, Device};
|
|||
/// using the provided writer function, and then passes them to another
|
||||
/// device.
|
||||
pub struct Tracer<T: Device, U: PrettyPrint> {
|
||||
lower: T,
|
||||
writer: fn(PrettyPrinter<U>)
|
||||
lower: T,
|
||||
writer: fn(u64, PrettyPrinter<U>)
|
||||
}
|
||||
|
||||
impl<T: Device, U: PrettyPrint> Tracer<T, U> {
|
||||
/// Create a tracer device.
|
||||
pub fn new(lower: T, writer: fn(PrettyPrinter<U>)) -> Tracer<T, U> {
|
||||
Tracer {
|
||||
lower: lower,
|
||||
writer: writer
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a tracer device, printing to standard output.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn new_stdout(lower: T) -> Tracer<T, U> {
|
||||
fn writer<U: PrettyPrint>(printer: PrettyPrinter<U>) {
|
||||
print!("{}", printer)
|
||||
}
|
||||
|
||||
pub fn new(lower: T, writer: fn(timestamp: u64, printer: PrettyPrinter<U>)) -> Tracer<T, U> {
|
||||
Tracer {
|
||||
lower: lower,
|
||||
writer: writer
|
||||
|
@ -46,25 +33,23 @@ impl<T: Device, U: PrettyPrint> Device for Tracer<T, U> {
|
|||
|
||||
fn limits(&self) -> DeviceLimits { self.lower.limits() }
|
||||
|
||||
fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
|
||||
let buffer = self.lower.receive()?;
|
||||
(self.writer)(PrettyPrinter::<U>::new("<- ", &buffer));
|
||||
fn receive(&mut self, timestamp: u64) -> Result<Self::RxBuffer, Error> {
|
||||
let buffer = self.lower.receive(timestamp)?;
|
||||
(self.writer)(timestamp, PrettyPrinter::<U>::new("<- ", &buffer));
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
let buffer = self.lower.transmit(length)?;
|
||||
Ok(TxBuffer {
|
||||
buffer: buffer,
|
||||
writer: self.writer
|
||||
})
|
||||
fn transmit(&mut self, timestamp: u64, length: usize) -> Result<Self::TxBuffer, Error> {
|
||||
let buffer = self.lower.transmit(timestamp, length)?;
|
||||
Ok(TxBuffer { buffer, timestamp, writer: self.writer })
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct TxBuffer<T: AsRef<[u8]>, U: PrettyPrint> {
|
||||
buffer: T,
|
||||
writer: fn(PrettyPrinter<U>)
|
||||
buffer: T,
|
||||
timestamp: u64,
|
||||
writer: fn(u64, PrettyPrinter<U>)
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>, U: PrettyPrint> AsRef<[u8]>
|
||||
|
@ -79,6 +64,6 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>, U: PrettyPrint> AsMut<[u8]>
|
|||
|
||||
impl<T: AsRef<[u8]>, U: PrettyPrint> Drop for TxBuffer<T, U> {
|
||||
fn drop(&mut self) {
|
||||
(self.writer)(PrettyPrinter::<U>::new("-> ", &self.buffer));
|
||||
(self.writer)(self.timestamp, PrettyPrinter::<U>::new("-> ", &self.buffer));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue