Use storage::PacketBuffer for implementing socket::IcmpSocket.
This substantially increases its space efficiency.
This commit is contained in:
parent
9353c37a62
commit
3d12690009
|
@ -17,7 +17,7 @@ use smoltcp::phy::wait as phy_wait;
|
||||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
|
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
|
||||||
Ipv4Address, Icmpv4Repr, Icmpv4Packet};
|
Ipv4Address, Icmpv4Repr, Icmpv4Packet};
|
||||||
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
|
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
|
||||||
use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketBuffer, IcmpEndpoint};
|
use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketMetadata, IcmpEndpoint};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use byteorder::{ByteOrder, NetworkEndian};
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ fn main() {
|
||||||
let remote_addr = address;
|
let remote_addr = address;
|
||||||
let local_addr = Ipv4Address::new(192, 168, 69, 1);
|
let local_addr = Ipv4Address::new(192, 168, 69, 1);
|
||||||
|
|
||||||
let icmp_rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 256])]);
|
let icmp_rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::empty()], vec![0; 256]);
|
||||||
let icmp_tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 256])]);
|
let icmp_tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::empty()], vec![0; 256]);
|
||||||
let icmp_socket = IcmpSocket::new(icmp_rx_buffer, icmp_tx_buffer);
|
let icmp_socket = IcmpSocket::new(icmp_rx_buffer, icmp_tx_buffer);
|
||||||
|
|
||||||
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
|
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
|
||||||
|
|
|
@ -1564,13 +1564,13 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
||||||
fn test_icmpv4_socket() {
|
fn test_icmpv4_socket() {
|
||||||
use socket::{IcmpPacketBuffer, IcmpSocket, IcmpSocketBuffer, IcmpEndpoint};
|
use socket::{IcmpSocket, IcmpEndpoint, IcmpSocketBuffer, IcmpPacketMetadata};
|
||||||
use wire::Icmpv4Packet;
|
use wire::Icmpv4Packet;
|
||||||
|
|
||||||
let (iface, mut socket_set) = create_loopback();
|
let (iface, mut socket_set) = create_loopback();
|
||||||
|
|
||||||
let rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 24])]);
|
let rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::empty()], vec![0; 24]);
|
||||||
let tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 24])]);
|
let tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::empty()], vec![0; 24]);
|
||||||
|
|
||||||
let icmpv4_socket = IcmpSocket::new(rx_buffer, tx_buffer);
|
let icmpv4_socket = IcmpSocket::new(rx_buffer, tx_buffer);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use managed::Managed;
|
|
||||||
|
|
||||||
use {Error, Result};
|
use {Error, Result};
|
||||||
use phy::{ChecksumCapabilities, DeviceCapabilities};
|
use phy::{ChecksumCapabilities, DeviceCapabilities};
|
||||||
use socket::{Socket, SocketMeta, SocketHandle};
|
use socket::{Socket, SocketMeta, SocketHandle};
|
||||||
use storage::{Resettable, RingBuffer};
|
use storage::{PacketBuffer, PacketMetadata};
|
||||||
use time::Instant;
|
use time::Instant;
|
||||||
use wire::{IpAddress, IpEndpoint, IpProtocol, IpRepr};
|
use wire::{IpAddress, IpEndpoint, IpProtocol, IpRepr};
|
||||||
use wire::{Ipv4Address, Ipv4Repr};
|
use wire::{Ipv4Address, Ipv4Repr};
|
||||||
|
@ -36,51 +35,11 @@ impl Default for Endpoint {
|
||||||
fn default() -> Endpoint { Endpoint::Unspecified }
|
fn default() -> Endpoint { Endpoint::Unspecified }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A buffered ICMPv4 packet.
|
/// An ICMPv4 packet metadata.
|
||||||
#[derive(Debug)]
|
pub type IcmpPacketMetadata = PacketMetadata<IpAddress>;
|
||||||
pub struct PacketBuffer<'a> {
|
|
||||||
endpoint: IpAddress,
|
|
||||||
size: usize,
|
|
||||||
payload: Managed<'a, [u8]>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PacketBuffer<'a> {
|
|
||||||
/// Create a buffered packet.
|
|
||||||
pub fn new<T>(payload: T) -> PacketBuffer<'a>
|
|
||||||
where T: Into<Managed<'a, [u8]>> {
|
|
||||||
PacketBuffer {
|
|
||||||
endpoint: IpAddress::default(),
|
|
||||||
size: 0,
|
|
||||||
payload: payload.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_ref<'b>(&'b self) -> &'b [u8] {
|
|
||||||
&self.payload[..self.size]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_mut<'b>(&'b mut self) -> &'b mut [u8] {
|
|
||||||
&mut self.payload[..self.size]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resize<'b>(&'b mut self, size: usize) -> Result<&'b mut Self> {
|
|
||||||
if self.payload.len() >= size {
|
|
||||||
self.size = size;
|
|
||||||
Ok(self)
|
|
||||||
} else {
|
|
||||||
Err(Error::Truncated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Resettable for PacketBuffer<'a> {
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An ICMPv4 packet ring buffer.
|
/// An ICMPv4 packet ring buffer.
|
||||||
pub type SocketBuffer<'a, 'b: 'a> = RingBuffer<'a, PacketBuffer<'b>>;
|
pub type IcmpSocketBuffer<'a, 'b> = PacketBuffer<'a, 'b, IpAddress>;
|
||||||
|
|
||||||
/// An ICMPv4 socket
|
/// An ICMPv4 socket
|
||||||
///
|
///
|
||||||
|
@ -94,8 +53,8 @@ pub type SocketBuffer<'a, 'b: 'a> = RingBuffer<'a, PacketBuffer<'b>>;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IcmpSocket<'a, 'b: 'a> {
|
pub struct IcmpSocket<'a, 'b: 'a> {
|
||||||
pub(crate) meta: SocketMeta,
|
pub(crate) meta: SocketMeta,
|
||||||
rx_buffer: SocketBuffer<'a, 'b>,
|
rx_buffer: IcmpSocketBuffer<'a, 'b>,
|
||||||
tx_buffer: SocketBuffer<'a, 'b>,
|
tx_buffer: IcmpSocketBuffer<'a, 'b>,
|
||||||
/// The endpoint this socket is communicating with
|
/// The endpoint this socket is communicating with
|
||||||
endpoint: Endpoint,
|
endpoint: Endpoint,
|
||||||
/// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
|
/// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
|
||||||
|
@ -104,8 +63,8 @@ pub struct IcmpSocket<'a, 'b: 'a> {
|
||||||
|
|
||||||
impl<'a, 'b> IcmpSocket<'a, 'b> {
|
impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
/// Create an ICMPv4 socket with the given buffers.
|
/// Create an ICMPv4 socket with the given buffers.
|
||||||
pub fn new(rx_buffer: SocketBuffer<'a, 'b>,
|
pub fn new(rx_buffer: IcmpSocketBuffer<'a, 'b>,
|
||||||
tx_buffer: SocketBuffer<'a, 'b>) -> IcmpSocket<'a, 'b> {
|
tx_buffer: IcmpSocketBuffer<'a, 'b>) -> IcmpSocket<'a, 'b> {
|
||||||
IcmpSocket {
|
IcmpSocket {
|
||||||
meta: SocketMeta::default(),
|
meta: SocketMeta::default(),
|
||||||
rx_buffer: rx_buffer,
|
rx_buffer: rx_buffer,
|
||||||
|
@ -164,9 +123,9 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
/// diagnose connection problems.
|
/// diagnose connection problems.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use smoltcp::socket::{Socket, IcmpSocket, IcmpPacketBuffer, IcmpSocketBuffer};
|
/// # use smoltcp::socket::{Socket, IcmpSocket, IcmpSocketBuffer, IcmpPacketMetadata};
|
||||||
/// # let rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 20])]);
|
/// # let rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::empty()], vec![0; 20]);
|
||||||
/// # let tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 20])]);
|
/// # let tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::empty()], vec![0; 20]);
|
||||||
/// use smoltcp::wire::IpEndpoint;
|
/// use smoltcp::wire::IpEndpoint;
|
||||||
/// use smoltcp::socket::IcmpEndpoint;
|
/// use smoltcp::socket::IcmpEndpoint;
|
||||||
///
|
///
|
||||||
|
@ -186,9 +145,9 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
/// messages.
|
/// messages.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use smoltcp::socket::{Socket, IcmpSocket, IcmpPacketBuffer, IcmpSocketBuffer};
|
/// # use smoltcp::socket::{Socket, IcmpSocket, IcmpSocketBuffer, IcmpPacketMetadata};
|
||||||
/// # let rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 20])]);
|
/// # let rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::empty()], vec![0; 20]);
|
||||||
/// # let tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 20])]);
|
/// # let tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::empty()], vec![0; 20]);
|
||||||
/// use smoltcp::socket::IcmpEndpoint;
|
/// use smoltcp::socket::IcmpEndpoint;
|
||||||
///
|
///
|
||||||
/// let mut icmp_socket = // ...
|
/// let mut icmp_socket = // ...
|
||||||
|
@ -244,11 +203,11 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
return Err(Error::Unaddressable)
|
return Err(Error::Unaddressable)
|
||||||
}
|
}
|
||||||
|
|
||||||
let packet_buf = self.tx_buffer.enqueue_one_with(|buf| buf.resize(size))?;
|
let packet_buf = self.tx_buffer.enqueue(size, endpoint)?;
|
||||||
packet_buf.endpoint = endpoint;
|
|
||||||
net_trace!("{}:{}: buffer to send {} octets",
|
net_trace!("{}:{}: buffer to send {} octets",
|
||||||
self.meta.handle, packet_buf.endpoint, size);
|
self.meta.handle, endpoint, size);
|
||||||
Ok(&mut packet_buf.as_mut()[..size])
|
Ok(packet_buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enqueue a packet to be sent to a given remote address, and fill it from a slice.
|
/// Enqueue a packet to be sent to a given remote address, and fill it from a slice.
|
||||||
|
@ -265,10 +224,11 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
///
|
///
|
||||||
/// This function returns `Err(Error::Exhausted)` if the receive buffer is empty.
|
/// This function returns `Err(Error::Exhausted)` if the receive buffer is empty.
|
||||||
pub fn recv(&mut self) -> Result<(&[u8], IpAddress)> {
|
pub fn recv(&mut self) -> Result<(&[u8], IpAddress)> {
|
||||||
let packet_buf = self.rx_buffer.dequeue_one()?;
|
let (endpoint, packet_buf) = self.rx_buffer.dequeue()?;
|
||||||
|
|
||||||
net_trace!("{}:{}: receive {} buffered octets",
|
net_trace!("{}:{}: receive {} buffered octets",
|
||||||
self.meta.handle, packet_buf.endpoint, packet_buf.size);
|
self.meta.handle, endpoint, packet_buf.len());
|
||||||
Ok((&packet_buf.as_ref(), packet_buf.endpoint))
|
Ok((packet_buf, endpoint))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dequeue a packet received from a remote endpoint, copy the payload into the given slice,
|
/// Dequeue a packet received from a remote endpoint, copy the payload into the given slice,
|
||||||
|
@ -309,29 +269,27 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process(&mut self, ip_repr: &IpRepr, icmp_repr: &Icmpv4Repr,
|
pub(crate) fn process(&mut self, ip_repr: &IpRepr, icmp_repr: &Icmpv4Repr,
|
||||||
cksum: &ChecksumCapabilities) -> Result<()> {
|
_cksum: &ChecksumCapabilities) -> Result<()> {
|
||||||
let packet_buf = self.rx_buffer.enqueue_one_with(|buf| buf.resize(icmp_repr.buffer_len()))?;
|
let packet_buf = self.rx_buffer.enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())?;
|
||||||
packet_buf.endpoint = ip_repr.src_addr();
|
icmp_repr.emit(&mut Icmpv4Packet::new(packet_buf), &ChecksumCapabilities::default());
|
||||||
|
|
||||||
net_trace!("{}:{}: receiving {} octets",
|
net_trace!("{}:{}: receiving {} octets",
|
||||||
self.meta.handle, packet_buf.endpoint, packet_buf.size);
|
self.meta.handle, icmp_repr.buffer_len(), packet_buf.len());
|
||||||
let mut packet = Icmpv4Packet::new(packet_buf.as_mut());
|
|
||||||
icmp_repr.emit(&mut packet, cksum);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn dispatch<F>(&mut self, caps: &DeviceCapabilities, emit: F) -> Result<()>
|
pub(crate) fn dispatch<F>(&mut self, _caps: &DeviceCapabilities, emit: F) -> Result<()>
|
||||||
where F: FnOnce((IpRepr, Icmpv4Repr)) -> Result<()>
|
where F: FnOnce((IpRepr, Icmpv4Repr)) -> Result<()>
|
||||||
{
|
{
|
||||||
let handle = self.meta.handle;
|
let handle = self.meta.handle;
|
||||||
let hop_limit = self.hop_limit.unwrap_or(64);
|
let hop_limit = self.hop_limit.unwrap_or(64);
|
||||||
let checksum = &caps.checksum;
|
self.tx_buffer.dequeue_with(|remote_endpoint, packet_buf| {
|
||||||
self.tx_buffer.dequeue_one_with(|packet_buf| {
|
|
||||||
net_trace!("{}:{}: sending {} octets",
|
net_trace!("{}:{}: sending {} octets",
|
||||||
handle, packet_buf.endpoint, packet_buf.size);
|
handle, remote_endpoint, packet_buf.len());
|
||||||
match packet_buf.endpoint {
|
match *remote_endpoint {
|
||||||
IpAddress::Ipv4(ipv4_addr) => {
|
IpAddress::Ipv4(ipv4_addr) => {
|
||||||
let packet = Icmpv4Packet::new(packet_buf.as_ref());
|
let packet = Icmpv4Packet::new(&*packet_buf);
|
||||||
let repr = Icmpv4Repr::parse(&packet, checksum)?;
|
let repr = Icmpv4Repr::parse(&packet, &ChecksumCapabilities::default())?;
|
||||||
let ip_repr = IpRepr::Ipv4(Ipv4Repr {
|
let ip_repr = IpRepr::Ipv4(Ipv4Repr {
|
||||||
src_addr: Ipv4Address::default(),
|
src_addr: Ipv4Address::default(),
|
||||||
dst_addr: ipv4_addr,
|
dst_addr: ipv4_addr,
|
||||||
|
@ -367,23 +325,19 @@ mod test {
|
||||||
use wire::{IpAddress, Icmpv4DstUnreachable};
|
use wire::{IpAddress, Icmpv4DstUnreachable};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn buffer(packets: usize) -> SocketBuffer<'static, 'static> {
|
fn buffer(packets: usize) -> IcmpSocketBuffer<'static, 'static> {
|
||||||
let mut storage = vec![];
|
IcmpSocketBuffer::new(vec![IcmpPacketMetadata::empty(); packets], vec![0; 46 * packets])
|
||||||
for _ in 0..packets {
|
|
||||||
storage.push(PacketBuffer::new(vec![0; 46]))
|
|
||||||
}
|
|
||||||
SocketBuffer::new(storage)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn socket(rx_buffer: SocketBuffer<'static, 'static>,
|
fn socket(rx_buffer: IcmpSocketBuffer<'static, 'static>,
|
||||||
tx_buffer: SocketBuffer<'static, 'static>) -> IcmpSocket<'static, 'static> {
|
tx_buffer: IcmpSocketBuffer<'static, 'static>) -> IcmpSocket<'static, 'static> {
|
||||||
IcmpSocket::new(rx_buffer, tx_buffer)
|
IcmpSocket::new(rx_buffer, tx_buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
const REMOTE_IPV4: Ipv4Address = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
|
const REMOTE_IPV4: Ipv4Address = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
|
||||||
const LOCAL_IPV4: Ipv4Address = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
|
const LOCAL_IPV4: Ipv4Address = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
|
||||||
const REMOTE_IP: IpAddress = IpAddress::Ipv4(REMOTE_IPV4);
|
const REMOTE_IP: IpAddress = IpAddress::Ipv4(REMOTE_IPV4);
|
||||||
const LOCAL_IP: IpAddress = IpAddress::Ipv4(LOCAL_IPV4);
|
const LOCAL_IP: IpAddress = IpAddress::Ipv4(LOCAL_IPV4);
|
||||||
const LOCAL_PORT: u16 = 53;
|
const LOCAL_PORT: u16 = 53;
|
||||||
const LOCAL_END: IpEndpoint = IpEndpoint { addr: LOCAL_IP, port: LOCAL_PORT };
|
const LOCAL_END: IpEndpoint = IpEndpoint { addr: LOCAL_IP, port: LOCAL_PORT };
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,8 @@ pub use self::raw::{RawPacketMetadata,
|
||||||
RawSocket};
|
RawSocket};
|
||||||
|
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
||||||
pub use self::icmp::{PacketBuffer as IcmpPacketBuffer,
|
pub use self::icmp::{IcmpPacketMetadata,
|
||||||
SocketBuffer as IcmpSocketBuffer,
|
IcmpSocketBuffer,
|
||||||
Endpoint as IcmpEndpoint,
|
Endpoint as IcmpEndpoint,
|
||||||
IcmpSocket};
|
IcmpSocket};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue