From 1d46ccf4322959a74a6ef85d7ef548519f6f2bf5 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 7 Mar 2017 10:56:48 +0000 Subject: [PATCH] =?UTF-8?q?fn=20Device::mtu()=20->=20usize=20=E2=86=92=20D?= =?UTF-8?q?evice::limits()=20->=20DeviceLimits?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/iface/ethernet.rs | 6 ++++-- src/phy/fault_injector.rs | 12 +++++------ src/phy/mod.rs | 44 ++++++++++++++++++++++++++++++++------- src/phy/raw_socket.rs | 9 ++++++-- src/phy/tap_interface.rs | 9 ++++++-- src/phy/tracer.rs | 4 ++-- src/socket/mod.rs | 5 +++-- src/socket/tcp.rs | 13 ++++++++---- src/socket/udp.rs | 3 ++- 9 files changed, 77 insertions(+), 28 deletions(-) diff --git a/src/iface/ethernet.rs b/src/iface/ethernet.rs index e240c4b..a09ed26 100644 --- a/src/iface/ethernet.rs +++ b/src/iface/ethernet.rs @@ -367,11 +367,13 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> { let src_protocol_addrs = self.protocol_addrs.as_ref(); let arp_cache = &mut self.arp_cache; let device = &mut self.device; - let mtu = device.mtu() - EthernetFrame::<&[u8]>::header_len(); + + let mut limits = device.limits(); + limits.max_transmission_unit -= EthernetFrame::<&[u8]>::header_len(); let mut nothing_to_transmit = true; for socket in sockets.iter_mut() { - let result = socket.dispatch(timestamp, mtu, &mut |repr, payload| { + let result = socket.dispatch(timestamp, &limits, &mut |repr, payload| { let repr = try!(repr.lower(src_protocol_addrs)); match arp_cache.lookup(&repr.dst_addr()) { diff --git a/src/phy/fault_injector.rs b/src/phy/fault_injector.rs index 03bb183..b75d2bc 100644 --- a/src/phy/fault_injector.rs +++ b/src/phy/fault_injector.rs @@ -1,5 +1,5 @@ use Error; -use super::Device; +use super::{DeviceLimits, Device}; // 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. @@ -98,12 +98,12 @@ impl Device for FaultInjector type RxBuffer = T::RxBuffer; type TxBuffer = TxBuffer; - fn mtu(&self) -> usize { - if self.lower.mtu() < MTU { - self.lower.mtu() - } else { - MTU + fn limits(&self) -> DeviceLimits { + let mut limits = self.lower.limits(); + if limits.max_transmission_unit > MTU { + limits.max_transmission_unit = MTU; } + limits } fn receive(&mut self) -> Result { diff --git a/src/phy/mod.rs b/src/phy/mod.rs index 50657fc..8cd78a0 100644 --- a/src/phy/mod.rs +++ b/src/phy/mod.rs @@ -18,7 +18,7 @@ ```rust use std::slice; use smoltcp::Error; -use smoltcp::phy::Device; +use smoltcp::phy::{DeviceLimits, Device}; const TX_BUFFERS: [*mut u8; 2] = [0x10000000 as *mut u8, 0x10001000 as *mut u8]; const RX_BUFFERS: [*mut u8; 2] = [0x10002000 as *mut u8, 0x10003000 as *mut u8]; @@ -50,7 +50,12 @@ impl Device for EthernetDevice { type RxBuffer = &'static [u8]; type TxBuffer = EthernetTxBuffer; - fn mtu(&self) -> usize { 1536 } + fn limits(&self) -> DeviceLimits { + let mut limits = DeviceLimits::default(); + limits.max_transmission_unit = 1536; + limits.max_burst_size = Some(2); + limits + } fn receive(&mut self) -> Result { if rx_full() { @@ -114,6 +119,34 @@ pub use self::raw_socket::RawSocket; #[cfg(all(feature = "std", target_os = "linux"))] pub use self::tap_interface::TapInterface; +/// A description of device limitations. +/// +/// Higher-level protocols may achieve higher throughput or lower latency if they consider +/// the bandwidth or packet size limitations. +#[derive(Debug, Clone, Default)] +pub struct DeviceLimits { + /// Maximum transmission unit. + /// + /// The network device is unable to send or receive frames larger than the value returned + /// by this function. + /// + /// For Ethernet, MTU will fall between 576 (for IPv4) or 1280 (for IPv6) and 9216 octets. + pub max_transmission_unit: usize, + + /// Maximum burst size, in terms of MTU. + /// + /// The network device is unable to send or receive bursts large than the value returned + /// by this function. + /// + /// If `None`, there is no fixed limit on burst size, e.g. if network buffers are + /// dynamically allocated. + pub max_burst_size: Option, + + /// Only present to prevent people from trying to initialize every field of DeviceLimits, + /// which would not let us add new fields in the future. + dummy: () +} + /// An interface for sending and receiving raw network frames. /// /// It is expected that a `Device` implementation would allocate memory for both sending @@ -123,11 +156,8 @@ pub trait Device { type RxBuffer: AsRef<[u8]>; type TxBuffer: AsRef<[u8]> + AsMut<[u8]>; - /// Get maximum transmission unit. - /// - /// The network device is unable to send or receive frames larger than the MTU. - /// In practice, MTU will fall between 576 (for IPv4) or 1280 (for IPv6) and 9216 octets. - fn mtu(&self) -> usize; + /// Get a description of device limitations. + fn limits(&self) -> DeviceLimits; /// Receive a frame. /// diff --git a/src/phy/raw_socket.rs b/src/phy/raw_socket.rs index 75adeea..bcea533 100644 --- a/src/phy/raw_socket.rs +++ b/src/phy/raw_socket.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use std::io; use Error; -use super::{sys, Device}; +use super::{sys, DeviceLimits, Device}; /// A socket that captures or transmits the complete frame. #[derive(Debug)] @@ -33,7 +33,12 @@ impl Device for RawSocket { type RxBuffer = Vec; type TxBuffer = TxBuffer; - fn mtu(&self) -> usize { self.mtu } + fn limits(&self) -> DeviceLimits { + DeviceLimits { + max_transmission_unit: self.mtu, + ..DeviceLimits::default() + } + } fn receive(&mut self) -> Result { let mut lower = self.lower.borrow_mut(); diff --git a/src/phy/tap_interface.rs b/src/phy/tap_interface.rs index 14b1231..575df28 100644 --- a/src/phy/tap_interface.rs +++ b/src/phy/tap_interface.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use std::io; use Error; -use super::{sys, Device}; +use super::{sys, DeviceLimits, Device}; /// A virtual Ethernet interface. #[derive(Debug)] @@ -33,7 +33,12 @@ impl Device for TapInterface { type RxBuffer = Vec; type TxBuffer = TxBuffer; - fn mtu(&self) -> usize { self.mtu } + fn limits(&self) -> DeviceLimits { + DeviceLimits { + max_transmission_unit: self.mtu, + ..DeviceLimits::default() + } + } fn receive(&mut self) -> Result { let mut lower = self.lower.borrow_mut(); diff --git a/src/phy/tracer.rs b/src/phy/tracer.rs index 6c32021..ee067cc 100644 --- a/src/phy/tracer.rs +++ b/src/phy/tracer.rs @@ -1,6 +1,6 @@ use Error; use wire::pretty_print::{PrettyPrint, PrettyPrinter}; -use super::Device; +use super::{DeviceLimits, Device}; /// A tracer device. /// @@ -43,7 +43,7 @@ impl Device for Tracer { type RxBuffer = T::RxBuffer; type TxBuffer = TxBuffer; - fn mtu(&self) -> usize { self.lower.mtu() } + fn limits(&self) -> DeviceLimits { self.lower.limits() } fn receive(&mut self) -> Result { let buffer = try!(self.lower.receive()); diff --git a/src/socket/mod.rs b/src/socket/mod.rs index 31565c0..ebc5ec0 100644 --- a/src/socket/mod.rs +++ b/src/socket/mod.rs @@ -11,6 +11,7 @@ //! size for a buffer, allocate it, and let the networking stack use it. use Error; +use phy::DeviceLimits; use wire::IpRepr; mod udp; @@ -92,10 +93,10 @@ impl<'a, 'b> Socket<'a, 'b> { /// is returned. /// /// This function is used internally by the networking stack. - pub fn dispatch(&mut self, timestamp: u64, mtu: usize, + pub fn dispatch(&mut self, timestamp: u64, limits: &DeviceLimits, emit: &mut F) -> Result where F: FnMut(&IpRepr, &IpPayload) -> Result { - dispatch_socket!(self, |socket [mut]| socket.dispatch(timestamp, mtu, emit)) + dispatch_socket!(self, |socket [mut]| socket.dispatch(timestamp, limits, emit)) } } diff --git a/src/socket/tcp.rs b/src/socket/tcp.rs index 732ccfa..47d39f2 100644 --- a/src/socket/tcp.rs +++ b/src/socket/tcp.rs @@ -2,6 +2,7 @@ use core::fmt; use managed::Managed; use Error; +use phy::DeviceLimits; use wire::{IpProtocol, IpAddress, IpEndpoint}; use wire::{TcpSeqNumber, TcpPacket, TcpRepr, TcpControl}; use socket::{Socket, IpRepr, IpPayload}; @@ -916,7 +917,7 @@ impl<'a> TcpSocket<'a> { } /// See [Socket::dispatch](enum.Socket.html#method.dispatch). - pub fn dispatch(&mut self, timestamp: u64, mtu: usize, + pub fn dispatch(&mut self, timestamp: u64, limits: &DeviceLimits, emit: &mut F) -> Result where F: FnMut(&IpRepr, &IpPayload) -> Result { if self.remote_endpoint.is_unspecified() { return Err(Error::Exhausted) } @@ -1080,8 +1081,10 @@ impl<'a> TcpSocket<'a> { let ip_repr = try!(ip_repr.lower(&[])); if repr.control == TcpControl::Syn { - let mtu = mtu - header_len - ip_repr.buffer_len(); - repr.max_seg_size = Some(mtu as u16); + let mut max_segment_size = limits.max_transmission_unit; + max_segment_size -= header_len; + max_segment_size -= ip_repr.buffer_len(); + repr.max_seg_size = Some(max_segment_size as u16); } emit(&ip_repr, &repr) @@ -1196,7 +1199,9 @@ mod test { fn recv(socket: &mut TcpSocket, timestamp: u64, mut f: F) where F: FnMut(Result) { let mut buffer = vec![]; - let result = socket.dispatch(timestamp, 1520, &mut |ip_repr, payload| { + let mut limits = DeviceLimits::default(); + limits.max_transmission_unit = 1520; + let result = socket.dispatch(timestamp, &limits, &mut |ip_repr, payload| { assert_eq!(ip_repr.protocol(), IpProtocol::Tcp); assert_eq!(ip_repr.src_addr(), LOCAL_IP); assert_eq!(ip_repr.dst_addr(), REMOTE_IP); diff --git a/src/socket/udp.rs b/src/socket/udp.rs index 28e0d93..0c5f0bb 100644 --- a/src/socket/udp.rs +++ b/src/socket/udp.rs @@ -1,6 +1,7 @@ use managed::Managed; use Error; +use phy::DeviceLimits; use wire::{IpProtocol, IpEndpoint}; use wire::{UdpPacket, UdpRepr}; use socket::{Socket, IpRepr, IpPayload}; @@ -232,7 +233,7 @@ impl<'a, 'b> UdpSocket<'a, 'b> { } /// See [Socket::dispatch](enum.Socket.html#method.dispatch). - pub fn dispatch(&mut self, _timestamp: u64, _mtu: usize, + pub fn dispatch(&mut self, _timestamp: u64, _limits: &DeviceLimits, emit: &mut F) -> Result where F: FnMut(&IpRepr, &IpPayload) -> Result { let packet_buf = try!(self.tx_buffer.dequeue().map_err(|()| Error::Exhausted));