Kaynağa Gözat

Update phy mod to use new time types

Update everything but the socket types to use the new time types instead
of a basic u64

Closes: #141
Approved by: whitequark
Dan Robertson 7 yıl önce
ebeveyn
işleme
470a08669f

+ 2 - 1
examples/tcpdump.rs

@@ -5,6 +5,7 @@ use std::os::unix::io::AsRawFd;
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::phy::{Device, RxToken, RawSocket};
 use smoltcp::wire::{PrettyPrinter, EthernetFrame};
+use smoltcp::time::Instant;
 
 fn main() {
     let ifname = env::args().nth(1).unwrap();
@@ -12,7 +13,7 @@ fn main() {
     loop {
         phy_wait(socket.as_raw_fd(), None).unwrap();
         let (rx_token, _) = socket.receive().unwrap();
-        rx_token.consume(/*timestamp = */ 0, |buffer| {
+        rx_token.consume(Instant::now(), |buffer| {
             println!("{}", PrettyPrinter::<EthernetFrame<&[u8]>>::new("", &buffer));
             Ok(())
         }).unwrap();

+ 2 - 2
examples/utils.rs

@@ -18,7 +18,7 @@ use smoltcp::phy::{Device, EthernetTracer, FaultInjector};
 #[cfg(feature = "phy-tap_interface")]
 use smoltcp::phy::TapInterface;
 use smoltcp::phy::{PcapWriter, PcapSink, PcapMode, PcapLinkType};
-use smoltcp::time::Instant;
+use smoltcp::time::{Duration, Instant};
 
 #[cfg(feature = "log")]
 pub fn setup_logging_with_clock<F>(filter: &str, since_startup: F)
@@ -138,6 +138,6 @@ pub fn parse_middleware_options<D>(matches: &mut Matches, device: D, loopback: b
     device.set_max_packet_size(size_limit);
     device.set_max_tx_rate(tx_rate_limit);
     device.set_max_rx_rate(rx_rate_limit);
-    device.set_bucket_interval(shaping_interval);
+    device.set_bucket_interval(Duration::from_millis(shaping_interval));
     device
 }

+ 28 - 27
src/iface/ethernet.rs

@@ -5,8 +5,8 @@ use core::cmp;
 use managed::ManagedSlice;
 
 use {Error, Result};
-use time::{Duration, Instant};
 use phy::{Device, DeviceCapabilities, RxToken, TxToken};
+use time::{Duration, Instant};
 use wire::pretty_print::PrettyPrinter;
 use wire::{EthernetAddress, EthernetProtocol, EthernetFrame};
 use wire::{IpAddress, IpProtocol, IpRepr, IpCidr};
@@ -341,7 +341,7 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
         sockets.iter().filter_map(|socket| {
             let socket_poll_at = socket.poll_at();
             socket.meta().poll_at(socket_poll_at, |ip_addr|
-                self.inner.has_neighbor(&ip_addr, timestamp.total_millis() as u64))
+                self.inner.has_neighbor(&ip_addr, timestamp))
         }).min().map(|x| Instant::from_millis(x as i64))
     }
 
@@ -373,15 +373,15 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
                 None => break,
                 Some(tokens) => tokens,
             };
-            rx_token.consume(timestamp.total_millis() as u64, |frame| {
-                inner.process_ethernet(sockets, timestamp.total_millis() as u64, &frame).map_err(|err| {
+            rx_token.consume(timestamp, |frame| {
+                inner.process_ethernet(sockets, timestamp, &frame).map_err(|err| {
                     net_debug!("cannot process ingress packet: {}", err);
                     net_debug!("packet dump follows:\n{}",
                                PrettyPrinter::<EthernetFrame<&[u8]>>::new("", &frame));
                     err
                 }).and_then(|response| {
                     processed_any = true;
-                    inner.dispatch(tx_token, timestamp.total_millis() as u64, response).map_err(|err| {
+                    inner.dispatch(tx_token, timestamp, response).map_err(|err| {
                         net_debug!("cannot dispatch response packet: {}", err);
                         err
                     })
@@ -398,7 +398,7 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
         let mut emitted_any = false;
         for mut socket in sockets.iter_mut() {
             if !socket.meta_mut().egress_permitted(|ip_addr|
-                    self.inner.has_neighbor(&ip_addr, timestamp.total_millis() as u64)) {
+                    self.inner.has_neighbor(&ip_addr, timestamp)) {
                 continue
             }
 
@@ -411,7 +411,7 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
                     let response = $response;
                     neighbor_addr = response.neighbor_addr();
                     let tx_token = device.transmit().ok_or(Error::Exhausted)?;
-                    device_result = inner.dispatch(tx_token, timestamp.total_millis() as u64, response);
+                    device_result = inner.dispatch(tx_token, timestamp, response);
                     device_result
                 })
             }
@@ -496,7 +496,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
     }
 
     fn process_ethernet<'frame, T: AsRef<[u8]>>
-                       (&mut self, sockets: &mut SocketSet, timestamp: u64, frame: &'frame T) ->
+                       (&mut self, sockets: &mut SocketSet, timestamp: Instant, frame: &'frame T) ->
                        Result<Packet<'frame>>
     {
         let eth_frame = EthernetFrame::new_checked(frame)?;
@@ -524,7 +524,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
 
     #[cfg(feature = "proto-ipv4")]
     fn process_arp<'frame, T: AsRef<[u8]>>
-                  (&mut self, timestamp: u64, eth_frame: &EthernetFrame<&'frame T>) ->
+                  (&mut self, timestamp: Instant, eth_frame: &EthernetFrame<&'frame T>) ->
                   Result<Packet<'frame>>
     {
         let arp_packet = ArpPacket::new_checked(eth_frame.payload())?;
@@ -588,7 +588,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
 
     #[cfg(feature = "proto-ipv6")]
     fn process_ipv6<'frame, T: AsRef<[u8]>>
-                   (&mut self, sockets: &mut SocketSet, timestamp: u64,
+                   (&mut self, sockets: &mut SocketSet, timestamp: Instant,
                     eth_frame: &EthernetFrame<&'frame T>) ->
                    Result<Packet<'frame>>
     {
@@ -625,7 +625,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
 
             #[cfg(feature = "socket-tcp")]
             IpProtocol::Tcp =>
-                self.process_tcp(sockets, timestamp, ip_repr, ip_payload),
+                self.process_tcp(sockets, timestamp.total_millis() as u64, ip_repr, ip_payload),
 
             #[cfg(feature = "socket-raw")]
             _ if handled_by_raw_socket =>
@@ -649,7 +649,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
 
     #[cfg(feature = "proto-ipv4")]
     fn process_ipv4<'frame, T: AsRef<[u8]>>
-                   (&mut self, sockets: &mut SocketSet, timestamp: u64,
+                   (&mut self, sockets: &mut SocketSet, timestamp: Instant,
                     eth_frame: &EthernetFrame<&'frame T>) ->
                    Result<Packet<'frame>>
     {
@@ -692,7 +692,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
 
             #[cfg(feature = "socket-tcp")]
             IpProtocol::Tcp =>
-                self.process_tcp(sockets, timestamp, ip_repr, ip_payload),
+                self.process_tcp(sockets, timestamp.total_millis() as u64, ip_repr, ip_payload),
 
             #[cfg(feature = "socket-raw")]
             _ if handled_by_raw_socket =>
@@ -917,7 +917,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
         }
     }
 
-    fn dispatch<Tx>(&mut self, tx_token: Tx, timestamp: u64,
+    fn dispatch<Tx>(&mut self, tx_token: Tx, timestamp: Instant,
                     packet: Packet) -> Result<()>
         where Tx: TxToken
     {
@@ -999,7 +999,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
         }
     }
 
-    fn dispatch_ethernet<Tx, F>(&mut self, tx_token: Tx, timestamp: u64,
+    fn dispatch_ethernet<Tx, F>(&mut self, tx_token: Tx, timestamp: Instant,
                                 buffer_len: usize, f: F) -> Result<()>
         where Tx: TxToken, F: FnOnce(EthernetFrame<&mut [u8]>)
     {
@@ -1039,7 +1039,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
         }
     }
 
-    fn has_neighbor<'a>(&self, addr: &'a IpAddress, timestamp: u64) -> bool {
+    fn has_neighbor<'a>(&self, addr: &'a IpAddress, timestamp: Instant) -> bool {
         match self.route(addr) {
             Ok(routed_addr) => {
                 self.neighbor_cache
@@ -1050,7 +1050,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
         }
     }
 
-    fn lookup_hardware_addr<Tx>(&mut self, tx_token: Tx, timestamp: u64,
+    fn lookup_hardware_addr<Tx>(&mut self, tx_token: Tx, timestamp: Instant,
                                 src_addr: &IpAddress, dst_addr: &IpAddress) ->
                                Result<(EthernetAddress, Tx)>
         where Tx: TxToken
@@ -1092,7 +1092,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
         }
     }
 
-    fn dispatch_ip<Tx, F>(&mut self, tx_token: Tx, timestamp: u64,
+    fn dispatch_ip<Tx, F>(&mut self, tx_token: Tx, timestamp: Instant,
                           ip_repr: IpRepr, f: F) -> Result<()>
         where Tx: TxToken, F: FnOnce(IpRepr, &mut [u8])
     {
@@ -1129,6 +1129,7 @@ mod test {
     use super::InterfaceBuilder;
     use iface::{NeighborCache, EthernetInterface};
     use phy::{self, Loopback, ChecksumCapabilities};
+    use time::Instant;
     use socket::SocketSet;
     #[cfg(feature = "proto-ipv4")]
     use wire::{ArpOperation, ArpPacket, ArpRepr};
@@ -1171,7 +1172,7 @@ mod test {
     struct MockTxToken;
 
     impl phy::TxToken for MockTxToken {
-        fn consume<R, F>(self, _: u64, _: usize, _: F) -> Result<R>
+        fn consume<R, F>(self, _: Instant, _: usize, _: F) -> Result<R>
                 where F: FnOnce(&mut [u8]) -> Result<R> {
             Err(Error::__Nonexhaustive)
         }
@@ -1215,7 +1216,7 @@ mod test {
         // Ensure that the unknown protocol frame does not trigger an
         // ICMP error response when the destination address is a
         // broadcast address
-        assert_eq!(iface.inner.process_ipv4(&mut socket_set, 0, &frame),
+        assert_eq!(iface.inner.process_ipv4(&mut socket_set, Instant::from_millis(0), &frame),
                    Ok(Packet::None));
     }
 
@@ -1273,7 +1274,7 @@ mod test {
 
         // Ensure that the unknown protocol triggers an error response.
         // And we correctly handle no payload.
-        assert_eq!(iface.inner.process_ipv4(&mut socket_set, 0, &frame),
+        assert_eq!(iface.inner.process_ipv4(&mut socket_set, Instant::from_millis(0), &frame),
                    Ok(expected_repr));
     }
 
@@ -1507,7 +1508,7 @@ mod test {
         }
 
         // Ensure an ARP Request for us triggers an ARP Reply
-        assert_eq!(iface.inner.process_ethernet(&mut socket_set, 0, frame.into_inner()),
+        assert_eq!(iface.inner.process_ethernet(&mut socket_set, Instant::from_millis(0), frame.into_inner()),
                    Ok(Packet::Arp(ArpRepr::EthernetIpv4 {
                        operation: ArpOperation::Reply,
                        source_hardware_addr: local_hw_addr,
@@ -1517,7 +1518,7 @@ mod test {
                    })));
 
         // Ensure the address of the requestor was entered in the cache
-        assert_eq!(iface.inner.lookup_hardware_addr(MockTxToken, 0,
+        assert_eq!(iface.inner.lookup_hardware_addr(MockTxToken, Instant::from_secs(0),
             &IpAddress::Ipv4(local_ip_addr), &IpAddress::Ipv4(remote_ip_addr)),
             Ok((remote_hw_addr, MockTxToken)));
     }
@@ -1550,11 +1551,11 @@ mod test {
         }
 
         // Ensure an ARP Request for someone else does not trigger an ARP Reply
-        assert_eq!(iface.inner.process_ethernet(&mut socket_set, 0, frame.into_inner()),
+        assert_eq!(iface.inner.process_ethernet(&mut socket_set, Instant::from_millis(0), frame.into_inner()),
                    Ok(Packet::None));
 
         // Ensure the address of the requestor was entered in the cache
-        assert_eq!(iface.inner.lookup_hardware_addr(MockTxToken, 0,
+        assert_eq!(iface.inner.lookup_hardware_addr(MockTxToken, Instant::from_secs(0),
             &IpAddress::Ipv4(Ipv4Address([0x7f, 0x00, 0x00, 0x01])),
             &IpAddress::Ipv4(remote_ip_addr)),
             Ok((remote_hw_addr, MockTxToken)));
@@ -1673,11 +1674,11 @@ mod test {
 
         // Ensure the unknown next header causes a ICMPv6 Parameter Problem
         // error message to be sent to the sender.
-        assert_eq!(iface.inner.process_ipv6(&mut socket_set, 0, &frame),
+        assert_eq!(iface.inner.process_ipv6(&mut socket_set, Instant::from_millis(0), &frame),
                    Ok(Packet::Icmpv6((reply_ipv6_repr, reply_icmp_repr))));
 
         // Ensure the address of the requestor was entered in the cache
-        assert_eq!(iface.inner.lookup_hardware_addr(MockTxToken, 0,
+        assert_eq!(iface.inner.lookup_hardware_addr(MockTxToken, Instant::from_secs(0),
             &IpAddress::Ipv6(Ipv6Address::LOOPBACK),
             &IpAddress::Ipv6(remote_ip_addr)),
             Ok((remote_hw_addr, MockTxToken)));

+ 37 - 34
src/iface/neighbor.rs

@@ -4,6 +4,7 @@
 use managed::ManagedMap;
 
 use wire::{EthernetAddress, IpAddress};
+use time::{Duration, Instant};
 
 /// A cached neighbor.
 ///
@@ -12,7 +13,7 @@ use wire::{EthernetAddress, IpAddress};
 #[derive(Debug, Clone, Copy)]
 pub struct Neighbor {
     hardware_addr: EthernetAddress,
-    expires_at:    u64,
+    expires_at:    Instant,
 }
 
 /// An answer to a neighbor cache lookup.
@@ -49,15 +50,15 @@ pub(crate) enum Answer {
 #[derive(Debug)]
 pub struct Cache<'a> {
     storage:      ManagedMap<'a, IpAddress, Neighbor>,
-    silent_until: u64,
+    silent_until: Instant,
 }
 
 impl<'a> Cache<'a> {
     /// Minimum delay between discovery requests, in milliseconds.
-    pub(crate) const SILENT_TIME: u64 = 1_000;
+    pub(crate) const SILENT_TIME: Duration = Duration { millis: 1_000 };
 
     /// Neighbor entry lifetime, in milliseconds.
-    pub(crate) const ENTRY_LIFETIME: u64 = 60_000;
+    pub(crate) const ENTRY_LIFETIME: Duration = Duration { millis: 60_000 };
 
     /// Create a cache. The backing storage is cleared upon creation.
     ///
@@ -68,11 +69,11 @@ impl<'a> Cache<'a> {
         let mut storage = storage.into();
         storage.clear();
 
-        Cache { storage, silent_until: 0 }
+        Cache { storage, silent_until: Instant::from_millis(0) }
     }
 
     pub(crate) fn fill(&mut self, protocol_addr: IpAddress, hardware_addr: EthernetAddress,
-                       timestamp: u64) {
+                       timestamp: Instant) {
         debug_assert!(protocol_addr.is_unicast());
         debug_assert!(hardware_addr.is_unicast());
 
@@ -125,7 +126,7 @@ impl<'a> Cache<'a> {
         }
     }
 
-    pub(crate) fn lookup_pure(&self, protocol_addr: &IpAddress, timestamp: u64) ->
+    pub(crate) fn lookup_pure(&self, protocol_addr: &IpAddress, timestamp: Instant) ->
                              Option<EthernetAddress> {
         if protocol_addr.is_broadcast() {
             return Some(EthernetAddress::BROADCAST)
@@ -143,7 +144,7 @@ impl<'a> Cache<'a> {
         None
     }
 
-    pub(crate) fn lookup(&mut self, protocol_addr: &IpAddress, timestamp: u64) -> Answer {
+    pub(crate) fn lookup(&mut self, protocol_addr: &IpAddress, timestamp: Instant) -> Answer {
         match self.lookup_pure(protocol_addr, timestamp) {
             Some(hardware_addr) =>
                 Answer::Found(hardware_addr),
@@ -172,16 +173,17 @@ mod test {
         let mut cache_storage = [Default::default(); 3];
         let mut cache = Cache::new(&mut cache_storage[..]);
 
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), None);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 0), None);
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, Instant::from_millis(0)), None);
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, Instant::from_millis(0)), None);
 
-        cache.fill(MOCK_IP_ADDR_1, HADDR_A, 0);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), Some(HADDR_A));
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 0), None);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 2 * Cache::ENTRY_LIFETIME), None);
+        cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, Instant::from_millis(0)), Some(HADDR_A));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, Instant::from_millis(0)), None);
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, Instant::from_millis(0) + Cache::ENTRY_LIFETIME * 2),
+                   None);
 
-        cache.fill(MOCK_IP_ADDR_1, HADDR_A, 0);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 0), None);
+        cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, Instant::from_millis(0)), None);
     }
 
     #[test]
@@ -189,9 +191,10 @@ mod test {
         let mut cache_storage = [Default::default(); 3];
         let mut cache = Cache::new(&mut cache_storage[..]);
 
-        cache.fill(MOCK_IP_ADDR_1, HADDR_A, 0);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), Some(HADDR_A));
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 2 * Cache::ENTRY_LIFETIME), None);
+        cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, Instant::from_millis(0)), Some(HADDR_A));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, Instant::from_millis(0) + Cache::ENTRY_LIFETIME * 2),
+                   None);
     }
 
     #[test]
@@ -199,10 +202,10 @@ mod test {
         let mut cache_storage = [Default::default(); 3];
         let mut cache = Cache::new(&mut cache_storage[..]);
 
-        cache.fill(MOCK_IP_ADDR_1, HADDR_A, 0);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), Some(HADDR_A));
-        cache.fill(MOCK_IP_ADDR_1, HADDR_B, 0);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), Some(HADDR_B));
+        cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, Instant::from_millis(0)), Some(HADDR_A));
+        cache.fill(MOCK_IP_ADDR_1, HADDR_B, Instant::from_millis(0));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, Instant::from_millis(0)), Some(HADDR_B));
     }
 
     #[test]
@@ -210,15 +213,15 @@ mod test {
         let mut cache_storage = [Default::default(); 3];
         let mut cache = Cache::new(&mut cache_storage[..]);
 
-        cache.fill(MOCK_IP_ADDR_1, HADDR_A, 100);
-        cache.fill(MOCK_IP_ADDR_2, HADDR_B, 50);
-        cache.fill(MOCK_IP_ADDR_3, HADDR_C, 200);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 1000), Some(HADDR_B));
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_4, 1000), None);
+        cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(100));
+        cache.fill(MOCK_IP_ADDR_2, HADDR_B, Instant::from_millis(50));
+        cache.fill(MOCK_IP_ADDR_3, HADDR_C, Instant::from_millis(200));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, Instant::from_millis(1000)), Some(HADDR_B));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_4, Instant::from_millis(1000)), None);
 
-        cache.fill(MOCK_IP_ADDR_4, HADDR_D, 300);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 1000), None);
-        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_4, 1000), Some(HADDR_D));
+        cache.fill(MOCK_IP_ADDR_4, HADDR_D, Instant::from_millis(300));
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, Instant::from_millis(1000)), None);
+        assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_4, Instant::from_millis(1000)), Some(HADDR_D));
     }
 
     #[test]
@@ -226,8 +229,8 @@ mod test {
         let mut cache_storage = [Default::default(); 3];
         let mut cache = Cache::new(&mut cache_storage[..]);
 
-        assert_eq!(cache.lookup(&MOCK_IP_ADDR_1, 0), Answer::NotFound);
-        assert_eq!(cache.lookup(&MOCK_IP_ADDR_1, 100), Answer::RateLimited);
-        assert_eq!(cache.lookup(&MOCK_IP_ADDR_1, 2000), Answer::NotFound);
+        assert_eq!(cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0)), Answer::NotFound);
+        assert_eq!(cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(100)), Answer::RateLimited);
+        assert_eq!(cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(2000)), Answer::NotFound);
     }
 }

+ 13 - 12
src/phy/fault_injector.rs

@@ -2,6 +2,7 @@ use core::cell::RefCell;
 
 use {Error, Result};
 use phy::{self, DeviceCapabilities, Device};
+use time::{Duration, Instant};
 
 // 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.
@@ -17,7 +18,7 @@ fn xorshift32(state: &mut u32) -> u32 {
 // This could be fixed once associated consts are stable.
 const MTU: usize = 1536;
 
-#[derive(Debug, Clone, Copy, Default)]
+#[derive(Debug, Default, Clone, Copy)]
 struct Config {
     corrupt_pct: u8,
     drop_pct:    u8,
@@ -25,13 +26,13 @@ struct Config {
     max_size:    usize,
     max_tx_rate: u64,
     max_rx_rate: u64,
-    interval:    u64,
+    interval:    Duration,
 }
 
 #[derive(Debug, Clone)]
 struct State {
     rng_seed:    u32,
-    refilled_at: u64,
+    refilled_at: Instant,
     tx_bucket:   u64,
     rx_bucket:   u64,
 }
@@ -49,7 +50,7 @@ impl State {
         buffer[index] ^= bit;
     }
 
-    fn refill(&mut self, config: &Config, timestamp: u64) {
+    fn refill(&mut self, config: &Config, timestamp: Instant) {
         if timestamp - self.refilled_at > config.interval {
             self.tx_bucket = config.max_tx_rate;
             self.rx_bucket = config.max_rx_rate;
@@ -57,7 +58,7 @@ impl State {
         }
     }
 
-    fn maybe_transmit(&mut self, config: &Config, timestamp: u64) -> bool {
+    fn maybe_transmit(&mut self, config: &Config, timestamp: Instant) -> bool {
         if config.max_tx_rate == 0 { return true }
 
         self.refill(config, timestamp);
@@ -69,7 +70,7 @@ impl State {
         }
     }
 
-    fn maybe_receive(&mut self, config: &Config, timestamp: u64) -> bool {
+    fn maybe_receive(&mut self, config: &Config, timestamp: Instant) -> bool {
         if config.max_rx_rate == 0 { return true }
 
         self.refill(config, timestamp);
@@ -99,7 +100,7 @@ impl<D: for<'a> Device<'a>> FaultInjector<D> {
     pub fn new(inner: D, seed: u32) -> FaultInjector<D> {
         let state = State {
             rng_seed:    seed,
-            refilled_at: 0,
+            refilled_at: Instant::from_millis(0),
             tx_bucket:   0,
             rx_bucket:   0,
         };
@@ -141,7 +142,7 @@ impl<D: for<'a> Device<'a>> FaultInjector<D> {
     }
 
     /// Return the interval for packet rate limiting, in milliseconds.
-    pub fn bucket_interval(&self) -> u64 {
+    pub fn bucket_interval(&self) -> Duration {
         self.config.interval
     }
 
@@ -179,8 +180,8 @@ impl<D: for<'a> Device<'a>> FaultInjector<D> {
     }
 
     /// Set the interval for packet rate limiting, in milliseconds.
-    pub fn set_bucket_interval(&mut self, interval: u64) {
-        self.state.borrow_mut().refilled_at = 0;
+    pub fn set_bucket_interval(&mut self, interval: Duration) {
+        self.state.borrow_mut().refilled_at = Instant::from_millis(0);
         self.config.interval = interval
     }
 }
@@ -238,7 +239,7 @@ pub struct RxToken<'a, Rx: phy::RxToken> {
 }
 
 impl<'a, Rx: phy::RxToken> phy::RxToken for RxToken<'a, Rx> {
-    fn consume<R, F>(self, timestamp: u64, f: F) -> Result<R>
+    fn consume<R, F>(self, timestamp: Instant, f: F) -> Result<R>
         where F: FnOnce(&[u8]) -> Result<R>
     {
         if self.state.borrow_mut().maybe(self.config.drop_pct) {
@@ -277,7 +278,7 @@ pub struct TxToken<'a, Tx: phy::TxToken> {
 }
 
 impl<'a, Tx: phy::TxToken> phy::TxToken for TxToken<'a, Tx> {
-    fn consume<R, F>(mut self, timestamp: u64, len: usize, f: F) -> Result<R>
+    fn consume<R, F>(mut self, timestamp: Instant, len: usize, f: F) -> Result<R>
         where F: FnOnce(&mut [u8]) -> Result<R>
     {
         let drop = if self.state.borrow_mut().maybe(self.config.drop_pct) {

+ 3 - 2
src/phy/loopback.rs

@@ -7,6 +7,7 @@ use alloc::{Vec, VecDeque};
 
 use Result;
 use phy::{self, Device, DeviceCapabilities};
+use time::Instant;
 
 /// A loopback device.
 #[derive(Debug)]
@@ -58,7 +59,7 @@ pub struct RxToken {
 }
 
 impl phy::RxToken for RxToken {
-    fn consume<R, F: FnOnce(&[u8]) -> Result<R>>(self, _timestamp: u64, f: F) -> Result<R> {
+    fn consume<R, F: FnOnce(&[u8]) -> Result<R>>(self, _timestamp: Instant, f: F) -> Result<R> {
         f(&self.buffer)
     }
 }
@@ -69,7 +70,7 @@ pub struct TxToken<'a> {
 }
 
 impl<'a> phy::TxToken for TxToken<'a> {
-    fn consume<R, F>(self, _timestamp: u64, len: usize, f: F) -> Result<R>
+    fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
         where F: FnOnce(&mut [u8]) -> Result<R>
     {
         let mut buffer = Vec::new();

+ 6 - 4
src/phy/mod.rs

@@ -19,6 +19,7 @@ Ethernet controller could look as follows:
 ```rust
 use smoltcp::Result;
 use smoltcp::phy::{self, DeviceCapabilities, Device};
+use smoltcp::time::Instant;
 
 struct StmPhy {
     rx_buffer: [u8; 1536],
@@ -58,7 +59,7 @@ impl<'a> phy::Device<'a> for StmPhy {
 struct StmPhyRxToken<'a>(&'a [u8]);
 
 impl<'a> phy::RxToken for StmPhyRxToken<'a> {
-    fn consume<R, F>(self, _timestamp: u64, f: F) -> Result<R>
+    fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
         where F: FnOnce(&[u8]) -> Result<R>
     {
         // TODO: receive packet into buffer
@@ -71,7 +72,7 @@ impl<'a> phy::RxToken for StmPhyRxToken<'a> {
 struct StmPhyTxToken<'a>(&'a mut [u8]);
 
 impl<'a> phy::TxToken for StmPhyTxToken<'a> {
-    fn consume<R, F>(self, _timestamp: u64, len: usize, f: F) -> Result<R>
+    fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
         where F: FnOnce(&mut [u8]) -> Result<R>
     {
         let result = f(&mut self.0[..len]);
@@ -84,6 +85,7 @@ impl<'a> phy::TxToken for StmPhyTxToken<'a> {
 */
 
 use Result;
+use time::Instant;
 
 #[cfg(any(feature = "phy-raw_socket", feature = "phy-tap_interface"))]
 mod sys;
@@ -245,7 +247,7 @@ pub trait RxToken {
     ///
     /// The timestamp must be a number of milliseconds, monotonically increasing since an
     /// arbitrary moment in time, such as system startup.
-    fn consume<R, F>(self, timestamp: u64, f: F) -> Result<R>
+    fn consume<R, F>(self, timestamp: Instant, f: F) -> Result<R>
         where F: FnOnce(&[u8]) -> Result<R>;
 }
 
@@ -260,6 +262,6 @@ pub trait TxToken {
     ///
     /// The timestamp must be a number of milliseconds, monotonically increasing since an
     /// arbitrary moment in time, such as system startup.
-    fn consume<R, F>(self, timestamp: u64, len: usize, f: F) -> Result<R>
+    fn consume<R, F>(self, timestamp: Instant, len: usize, f: F) -> Result<R>
         where F: FnOnce(&mut [u8]) -> Result<R>;
 }

+ 8 - 8
src/phy/pcap_writer.rs

@@ -6,6 +6,7 @@ use byteorder::{ByteOrder, NativeEndian};
 
 use Result;
 use phy::{self, DeviceCapabilities, Device};
+use time::Instant;
 
 enum_with_unknown! {
     /// Captured packet header type.
@@ -66,12 +67,11 @@ pub trait PcapSink {
     ///
     /// # Panics
     /// This function panics if `length` is greater than 65535.
-    fn packet_header(&self, timestamp: u64, length: usize) {
+    fn packet_header(&self, timestamp: Instant, length: usize) {
         assert!(length <= 65535);
 
-        let (seconds, micros) = (timestamp / 1000, timestamp % 1000 * 1000);
-        self.write_u32(seconds as u32);   // timestamp seconds
-        self.write_u32(micros  as u32);   // timestamp microseconds
+        self.write_u32(timestamp.secs() as u32);   // timestamp seconds
+        self.write_u32(timestamp.millis() as u32);   // timestamp microseconds
         self.write_u32(length  as u32);   // captured length
         self.write_u32(length  as u32);   // original length
     }
@@ -79,7 +79,7 @@ pub trait PcapSink {
     /// Write the libpcap packet header followed by packet data into the sink.
     ///
     /// See also the note for [global_header](#method.global_header).
-    fn packet(&self, timestamp: u64, packet: &[u8]) {
+    fn packet(&self, timestamp: Instant, packet: &[u8]) {
         self.packet_header(timestamp, packet.len());
         self.write(packet)
     }
@@ -97,7 +97,7 @@ impl<T: Write> PcapSink for RefCell<T> {
         self.borrow_mut().write_all(data).expect("cannot write")
     }
 
-    fn packet(&self, timestamp: u64, packet: &[u8]) {
+    fn packet(&self, timestamp: Instant, packet: &[u8]) {
         self.packet_header(timestamp, packet.len());
         PcapSink::write(self, packet);
         self.borrow_mut().flush().expect("cannot flush")
@@ -168,7 +168,7 @@ pub struct RxToken<Rx: phy::RxToken, S: PcapSink> {
 }
 
 impl<Rx: phy::RxToken, S: PcapSink> phy::RxToken for RxToken<Rx, S> {
-    fn consume<R, F: FnOnce(&[u8]) -> Result<R>>(self, timestamp: u64, f: F) -> Result<R> {
+    fn consume<R, F: FnOnce(&[u8]) -> Result<R>>(self, timestamp: Instant, f: F) -> Result<R> {
         let Self { token, sink, mode } = self;
         token.consume(timestamp, |buffer| {
             match mode {
@@ -189,7 +189,7 @@ pub struct TxToken<Tx: phy::TxToken, S: PcapSink> {
 }
 
 impl<Tx: phy::TxToken, S: PcapSink> phy::TxToken for TxToken<Tx, S> {
-    fn consume<R, F>(self, timestamp: u64, len: usize, f: F) -> Result<R>
+    fn consume<R, F>(self, timestamp: Instant, len: usize, f: F) -> Result<R>
         where F: FnOnce(&mut [u8]) -> Result<R>
     {
         let Self { token, sink, mode } = self;

+ 3 - 2
src/phy/raw_socket.rs

@@ -6,6 +6,7 @@ use std::os::unix::io::{RawFd, AsRawFd};
 
 use Result;
 use phy::{self, sys, DeviceCapabilities, Device};
+use time::Instant;
 
 /// A socket that captures or transmits the complete frame.
 #[derive(Debug)]
@@ -77,7 +78,7 @@ pub struct RxToken {
 }
 
 impl phy::RxToken for RxToken {
-    fn consume<R, F: FnOnce(&[u8]) -> Result<R>>(self, _timestamp: u64, f: F) -> Result<R> {
+    fn consume<R, F: FnOnce(&[u8]) -> Result<R>>(self, _timestamp: Instant, f: F) -> Result<R> {
         f(&self.buffer[..])
     }
 }
@@ -88,7 +89,7 @@ pub struct TxToken {
 }
 
 impl phy::TxToken for TxToken {
-    fn consume<R, F: FnOnce(&mut [u8]) -> Result<R>>(self, _timestamp: u64, len: usize, f: F)
+    fn consume<R, F: FnOnce(&mut [u8]) -> Result<R>>(self, _timestamp: Instant, len: usize, f: F)
         -> Result<R>
     {
         let mut lower = self.lower.borrow_mut();

+ 3 - 2
src/phy/tap_interface.rs

@@ -6,6 +6,7 @@ use std::os::unix::io::{RawFd, AsRawFd};
 
 use Result;
 use phy::{self, sys, DeviceCapabilities, Device};
+use time::Instant;
 
 /// A virtual Ethernet interface.
 #[derive(Debug)]
@@ -78,7 +79,7 @@ pub struct RxToken {
 }
 
 impl phy::RxToken for RxToken {
-    fn consume<R, F>(self, _timestamp: u64, f: F) -> Result<R>
+    fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
         where F: FnOnce(&[u8]) -> Result<R>
     {
         f(&self.buffer[..])
@@ -91,7 +92,7 @@ pub struct TxToken {
 }
 
 impl phy::TxToken for TxToken {
-    fn consume<R, F>(self, _timestamp: u64, len: usize, f: F) -> Result<R>
+    fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
         where F: FnOnce(&mut [u8]) -> Result<R>
     {
         let mut lower = self.lower.borrow_mut();

+ 7 - 6
src/phy/tracer.rs

@@ -1,6 +1,7 @@
 use Result;
 use wire::pretty_print::{PrettyPrint, PrettyPrinter};
 use phy::{self, DeviceCapabilities, Device};
+use time::Instant;
 
 /// A tracer device.
 ///
@@ -9,12 +10,12 @@ use phy::{self, DeviceCapabilities, Device};
 /// device.
 pub struct Tracer<D: for<'a> Device<'a>, P: PrettyPrint> {
     inner:  D,
-    writer: fn(u64, PrettyPrinter<P>),
+    writer: fn(Instant, PrettyPrinter<P>),
 }
 
 impl<D: for<'a> Device<'a>, P: PrettyPrint> Tracer<D, P> {
     /// Create a tracer device.
-    pub fn new(inner: D, writer: fn(timestamp: u64, printer: PrettyPrinter<P>)) -> Tracer<D, P> {
+    pub fn new(inner: D, writer: fn(timestamp: Instant, printer: PrettyPrinter<P>)) -> Tracer<D, P> {
         Tracer { inner, writer }
     }
 
@@ -53,11 +54,11 @@ impl<'a, D, P> Device<'a> for Tracer<D, P>
 #[doc(hidden)]
 pub struct RxToken<Rx: phy::RxToken, P: PrettyPrint> {
     token:     Rx,
-    writer:    fn(u64, PrettyPrinter<P>)
+    writer:    fn(Instant, PrettyPrinter<P>)
 }
 
 impl<Rx: phy::RxToken, P: PrettyPrint> phy::RxToken for RxToken<Rx, P> {
-    fn consume<R, F>(self, timestamp: u64, f: F) -> Result<R>
+    fn consume<R, F>(self, timestamp: Instant, f: F) -> Result<R>
         where F: FnOnce(&[u8]) -> Result<R>
     {
         let Self { token, writer } = self;
@@ -71,11 +72,11 @@ impl<Rx: phy::RxToken, P: PrettyPrint> phy::RxToken for RxToken<Rx, P> {
 #[doc(hidden)]
 pub struct TxToken<Tx: phy::TxToken, P: PrettyPrint> {
     token:     Tx,
-    writer:    fn(u64, PrettyPrinter<P>)
+    writer:    fn(Instant, PrettyPrinter<P>)
 }
 
 impl<Tx: phy::TxToken, P: PrettyPrint> phy::TxToken for TxToken<Tx, P> {
-    fn consume<R, F>(self, timestamp: u64, len: usize, f: F) -> Result<R>
+    fn consume<R, F>(self, timestamp: Instant, len: usize, f: F) -> Result<R>
         where F: FnOnce(&mut [u8]) -> Result<R>
     {
         let Self { token, writer } = self;

+ 2 - 1
utils/packet2pcap.rs

@@ -8,6 +8,7 @@ use std::fs::File;
 use std::env;
 use std::process::exit;
 use smoltcp::phy::{PcapLinkType, PcapSink};
+use smoltcp::time::Instant;
 use getopts::Options;
 
 fn convert(packet_filename: &Path, pcap_filename: &Path, link_type: PcapLinkType)
@@ -18,7 +19,7 @@ fn convert(packet_filename: &Path, pcap_filename: &Path, link_type: PcapLinkType
 
     let pcap = RefCell::new(Vec::new());
     PcapSink::global_header(&pcap, link_type);
-    PcapSink::packet(&pcap, 0, &packet[..]);
+    PcapSink::packet(&pcap, Instant::from_millis(0), &packet[..]);
 
     let mut pcap_file = File::create(pcap_filename)?;
     pcap_file.write_all(&pcap.borrow()[..])?;