Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7d54157e77b2
Choose a base ref
...
head repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 97499ac280cd
Choose a head ref
  • 3 commits
  • 13 files changed
  • 1 contributor

Commits on Jul 23, 2017

  1. Move macros into their own module.

    This allows us to use `enum_with_unknown` in `phy`.
    whitequark committed Jul 23, 2017
    Copy the full SHA
    f5a3785 View commit details
  2. 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 committed Jul 23, 2017
    Copy the full SHA
    3a656c1 View commit details
  3. Copy the full SHA
    97499ac View commit details
Showing with 136 additions and 154 deletions.
  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 −21 src/lib.rs
  6. +71 −0 src/macros.rs
  7. +18 −20 src/phy/fault_injector.rs
  8. +2 −2 src/phy/loopback.rs
  9. +4 −4 src/phy/mod.rs
  10. +2 −2 src/phy/raw_socket.rs
  11. +2 −2 src/phy/tap_interface.rs
  12. +23 −40 src/phy/tracer.rs
  13. +0 −53 src/wire/mod.rs
2 changes: 1 addition & 1 deletion examples/loopback.rs
Original file line number Diff line number Diff line change
@@ -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[..]);
2 changes: 1 addition & 1 deletion examples/tcpdump.rs
Original file line number Diff line number Diff line change
@@ -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))
}
}
2 changes: 1 addition & 1 deletion examples/utils.rs
Original file line number Diff line number Diff line change
@@ -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);
14 changes: 7 additions & 7 deletions src/iface/ethernet.rs
Original file line number Diff line number Diff line change
@@ -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);
25 changes: 4 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -84,35 +84,18 @@ extern crate collections;
#[macro_use(trace, log, log_enabled)]
extern crate log;

macro_rules! net_trace {
($($arg:expr),*) => {
#[cfg(feature = "log")]
trace!($($arg),*);
#[cfg(not(feature = "log"))]
$( let _ = $arg );*; // suppress unused variable warnings
}
}

macro_rules! net_trace_enabled {
() => ({
#[cfg(feature = "log")]
fn enabled() -> bool { log_enabled!($crate::log::LogLevel::Trace) }
#[cfg(not(feature = "log"))]
fn enabled() -> bool { false }
enabled()
})
}

use core::fmt;

#[macro_use]
mod macros;
mod parsing;

pub mod storage;
pub mod phy;
pub mod wire;
pub mod iface;
pub mod socket;

mod parsing;

/// The error type for the networking stack.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
71 changes: 71 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
macro_rules! net_trace {
($($arg:expr),*) => {
#[cfg(feature = "log")]
trace!($($arg),*);
#[cfg(not(feature = "log"))]
$( let _ = $arg );*; // suppress unused variable warnings
}
}

macro_rules! net_trace_enabled {
() => ({
#[cfg(feature = "log")]
fn enabled() -> bool { log_enabled!($crate::log::LogLevel::Trace) }
#[cfg(not(feature = "log"))]
fn enabled() -> bool { false }
enabled()
})
}

macro_rules! enum_with_unknown {
(
$( #[$enum_attr:meta] )*
pub enum $name:ident($ty:ty) {
$( $variant:ident = $value:expr ),+
}
) => {
enum_with_unknown! {
$( #[$enum_attr] )*
pub doc enum $name($ty) {
$( #[doc(shown)] $variant = $value ),+
}
}
};
(
$( #[$enum_attr:meta] )*
pub doc enum $name:ident($ty:ty) {
$(
$( #[$variant_attr:meta] )+
$variant:ident = $value:expr
),+
}
) => {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
$( #[$enum_attr] )*
pub enum $name {
$(
$( #[$variant_attr] )*
$variant
),*,
Unknown($ty)
}

impl ::core::convert::From<$ty> for $name {
fn from(value: $ty) -> Self {
match value {
$( $value => $name::$variant ),*,
other => $name::Unknown(other)
}
}
}

impl ::core::convert::From<$name> for $ty {
fn from(value: $name) -> Self {
match value {
$( $name::$variant => $value ),*,
$name::Unknown(other) => other
}
}
}
}
}
38 changes: 18 additions & 20 deletions src/phy/fault_injector.rs
Original file line number Diff line number Diff line change
@@ -108,15 +108,15 @@ impl State {
/// adverse network conditions (such as random packet loss or corruption), or software
/// or hardware limitations (such as a limited number or size of usable network buffers).
#[derive(Debug)]
pub struct FaultInjector<T: Device> {
lower: T,
pub struct FaultInjector<D: Device> {
lower: D,
state: State,
config: Config
}

impl<T: Device> FaultInjector<T> {
impl<D: Device> FaultInjector<D> {
/// Create a fault injector device, using the given random number generator seed.
pub fn new(lower: T, seed: u32) -> FaultInjector<T> {
pub fn new(lower: D, seed: u32) -> FaultInjector<D> {
#[cfg(feature = "std")]
let state = State {
rng_seed: seed,
@@ -136,7 +136,7 @@ impl<T: Device> FaultInjector<T> {
}

/// Return the underlying device, consuming the fault injector.
pub fn into_lower(self) -> T {
pub fn into_lower(self) -> D {
self.lower
}

@@ -216,10 +216,10 @@ impl<T: Device> FaultInjector<T> {
}
}

impl<T: Device> Device for FaultInjector<T>
where T::RxBuffer: AsMut<[u8]> {
type RxBuffer = T::RxBuffer;
type TxBuffer = TxBuffer<T::TxBuffer>;
impl<D: Device> Device for FaultInjector<D>
where D::RxBuffer: AsMut<[u8]> {
type RxBuffer = D::RxBuffer;
type TxBuffer = TxBuffer<D::TxBuffer>;

fn limits(&self) -> DeviceLimits {
let mut limits = self.lower.limits();
@@ -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,
@@ -275,16 +275,15 @@ impl<T: Device> Device for FaultInjector<T>
}

#[doc(hidden)]
pub struct TxBuffer<T: AsRef<[u8]> + AsMut<[u8]>> {
pub struct TxBuffer<B: AsRef<[u8]> + AsMut<[u8]>> {
state: State,
config: Config,
buffer: Option<T>,
buffer: Option<B>,
junk: [u8; MTU],
length: usize
}

impl<T: AsRef<[u8]> + AsMut<[u8]>> AsRef<[u8]>
for TxBuffer<T> {
impl<B: AsRef<[u8]> + AsMut<[u8]>> AsRef<[u8]> for TxBuffer<B> {
fn as_ref(&self) -> &[u8] {
match self.buffer {
Some(ref buf) => buf.as_ref(),
@@ -293,8 +292,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> AsRef<[u8]>
}
}

impl<T: AsRef<[u8]> + AsMut<[u8]>> AsMut<[u8]>
for TxBuffer<T> {
impl<B: AsRef<[u8]> + AsMut<[u8]>> AsMut<[u8]> for TxBuffer<B> {
fn as_mut(&mut self) -> &mut [u8] {
match self.buffer {
Some(ref mut buf) => buf.as_mut(),
@@ -303,7 +301,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> AsMut<[u8]>
}
}

impl<T: AsRef<[u8]> + AsMut<[u8]>> Drop for TxBuffer<T> {
impl<B: AsRef<[u8]> + AsMut<[u8]>> Drop for TxBuffer<B> {
fn drop(&mut self) {
match self.buffer {
Some(ref mut buf) => {
4 changes: 2 additions & 2 deletions src/phy/loopback.rs
Original file line number Diff line number Diff line change
@@ -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 {
8 changes: 4 additions & 4 deletions src/phy/mod.rs
Original file line number Diff line number Diff line change
@@ -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>;
}
4 changes: 2 additions & 2 deletions src/phy/raw_socket.rs
Original file line number Diff line number Diff line change
@@ -40,15 +40,15 @@ 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();
buffer.resize(size, 0);
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]
4 changes: 2 additions & 2 deletions src/phy/tap_interface.rs
Original file line number Diff line number Diff line change
@@ -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]
Loading