浏览代码

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.
whitequark 7 年之前
父节点
当前提交
3a656c1529
共有 10 个文件被更改,包括 37 次插入52 次删除
  1. 1 1
      examples/loopback.rs
  2. 1 1
      examples/tcpdump.rs
  3. 1 1
      examples/utils.rs
  4. 7 7
      src/iface/ethernet.rs
  5. 4 4
      src/phy/fault_injector.rs
  6. 2 2
      src/phy/loopback.rs
  7. 4 4
      src/phy/mod.rs
  8. 2 2
      src/phy/raw_socket.rs
  9. 2 2
      src/phy/tap_interface.rs
  10. 13 28
      src/phy/tracer.rs

+ 1 - 1
examples/loopback.rs

@@ -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[..]);

+ 1 - 1
examples/tcpdump.rs

@@ -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))
     }
 }

+ 1 - 1
examples/utils.rs

@@ -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);

+ 7 - 7
src/iface/ethernet.rs

@@ -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);

+ 4 - 4
src/phy/fault_injector.rs

@@ -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,

+ 2 - 2
src/phy/loopback.rs

@@ -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 {

+ 4 - 4
src/phy/mod.rs

@@ -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>;
 }

+ 2 - 2
src/phy/raw_socket.rs

@@ -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]

+ 2 - 2
src/phy/tap_interface.rs

@@ -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]

+ 13 - 28
src/phy/tracer.rs

@@ -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));
     }
 }