Replace EthernetInterface::new with EthernetInterfaceBuilder.

v0.7.x
Dan Robertson 2017-12-18 08:29:30 -05:00 committed by whitequark
parent 278bb4b2c9
commit 4a98190f9b
6 changed files with 173 additions and 45 deletions

View File

@ -12,7 +12,7 @@ use std::time::Instant;
use std::os::unix::io::AsRawFd;
use smoltcp::phy::wait as phy_wait;
use smoltcp::wire::{EthernetAddress, Ipv4Address, IpAddress, IpCidr};
use smoltcp::iface::{NeighborCache, EthernetInterface};
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
fn main() {
@ -42,8 +42,12 @@ fn main() {
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 2), 24)];
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
let mut iface = EthernetInterface::new(
device, neighbor_cache, ethernet_addr, ip_addrs, Some(default_v4_gw));
let mut iface = EthernetInterfaceBuilder::new(device)
.ethernet_addr(ethernet_addr)
.neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs)
.ipv4_gateway(default_v4_gw)
.finalize();
let mut sockets = SocketSet::new(vec![]);
let tcp_handle = sockets.add(tcp_socket);

View File

@ -18,7 +18,7 @@ mod utils;
use core::str;
use smoltcp::phy::Loopback;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
use smoltcp::iface::{NeighborCache, EthernetInterface};
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
#[cfg(not(feature = "std"))]
@ -89,8 +89,11 @@ fn main() {
let mut neighbor_cache = NeighborCache::new(&mut neighbor_cache_entries[..]);
let mut ip_addrs = [IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8)];
let mut iface = EthernetInterface::new(
device, neighbor_cache, EthernetAddress::default(), &mut ip_addrs[..], None);
let mut iface = EthernetInterfaceBuilder::new(device)
.ethernet_addr(EthernetAddress::default())
.neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs)
.finalize();
let server_socket = {
// It is not strictly necessary to use a `static mut` and unsafe code here, but

View File

@ -15,7 +15,7 @@ use smoltcp::phy::Device;
use smoltcp::phy::wait as phy_wait;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
Ipv4Address, Icmpv4Repr, Icmpv4Packet};
use smoltcp::iface::{NeighborCache, EthernetInterface};
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketBuffer, IcmpEndpoint};
use std::collections::HashMap;
use byteorder::{ByteOrder, NetworkEndian};
@ -58,8 +58,12 @@ fn main() {
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
let ip_addr = IpCidr::new(IpAddress::from(local_addr), 24);
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
let mut iface = EthernetInterface::new(
device, neighbor_cache, ethernet_addr, [ip_addr], Some(default_v4_gw));
let mut iface = EthernetInterfaceBuilder::new(device)
.ethernet_addr(ethernet_addr)
.ip_addrs([ip_addr])
.ipv4_gateway(default_v4_gw)
.neighbor_cache(neighbor_cache)
.finalize();
let mut sockets = SocketSet::new(vec![]);
let icmp_handle = sockets.add(icmp_socket);

View File

@ -13,7 +13,7 @@ use std::time::Instant;
use std::os::unix::io::AsRawFd;
use smoltcp::phy::wait as phy_wait;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
use smoltcp::iface::{NeighborCache, EthernetInterface};
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
use smoltcp::socket::SocketSet;
use smoltcp::socket::{UdpSocket, UdpSocketBuffer, UdpPacketBuffer};
use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
@ -56,8 +56,11 @@ fn main() {
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24)];
let mut iface = EthernetInterface::new(
device, neighbor_cache, ethernet_addr, ip_addrs, None);
let mut iface = EthernetInterfaceBuilder::new(device)
.ethernet_addr(ethernet_addr)
.neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs)
.finalize();
let mut sockets = SocketSet::new(vec![]);
let udp_handle = sockets.add(udp_socket);

View File

@ -54,6 +54,132 @@ struct InterfaceInner<'b, 'c> {
device_capabilities: DeviceCapabilities,
}
/// A builder structure used for creating a Ethernet network
/// interface.
pub struct InterfaceBuilder <'b, 'c, DeviceT: for<'d> Device<'d>> {
device: DeviceT,
ethernet_addr: Option<EthernetAddress>,
neighbor_cache: Option<NeighborCache<'b>>,
ip_addrs: Option<ManagedSlice<'c, IpCidr>>,
ipv4_gateway: Option<Ipv4Address>,
}
impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
where DeviceT: for<'d> Device<'d> {
/// Create a builder used for creating a network interface using the
/// given device and address.
///
/// # Examples
///
/// ```
/// # use std::collections::BTreeMap;
/// use smoltcp::iface::{EthernetInterfaceBuilder, NeighborCache};
/// # use smoltcp::phy::Loopback;
/// use smoltcp::wire::{EthernetAddress, IpCidr, IpAddress};
///
/// let device = // ...
/// # Loopback::new();
/// let hw_addr = // ...
/// # EthernetAddress::default();
/// let neighbor_cache = // ...
/// # NeighborCache::new(BTreeMap::new());
/// let ip_addrs = // ...
/// # [];
/// let iface = EthernetInterfaceBuilder::new(device)
/// .ethernet_addr(hw_addr)
/// .neighbor_cache(neighbor_cache)
/// .ip_addrs(ip_addrs)
/// .finalize();
/// ```
pub fn new(device: DeviceT) -> InterfaceBuilder<'b, 'c, DeviceT> {
InterfaceBuilder {
device: device,
ethernet_addr: None,
neighbor_cache: None,
ip_addrs: None,
ipv4_gateway: None
}
}
/// Set the Ethernet address the interface will use. See also
/// [ethernet_addr].
///
/// # Panics
/// This function panics if the address is not unicast.
///
/// [ethernet_addr]: struct.EthernetInterface.html#method.ethernet_addr
pub fn ethernet_addr(mut self, addr: EthernetAddress) -> InterfaceBuilder<'b, 'c, DeviceT> {
InterfaceInner::check_ethernet_addr(&addr);
self.ethernet_addr = Some(addr);
self
}
/// Set the IP addresses the interface will use. See also
/// [ip_addrs].
///
/// # Panics
/// This function panics if any of the addresses is not unicast.
///
/// [ip_addrs]: struct.EthernetInterface.html#method.ip_addrs
pub fn ip_addrs<T: Into<ManagedSlice<'c, IpCidr>>>(mut self, ips: T) -> InterfaceBuilder<'b, 'c, DeviceT> {
let ips = ips.into();
InterfaceInner::check_ip_addrs(&ips);
self.ip_addrs = Some(ips);
self
}
/// Set the IPv4 gateway the interface will use. See also
/// [ipv4_gateway].
///
/// # Panics
/// This function panics if the given address is not unicast.
///
/// [ipv4_gateway]: struct.EthernetInterface.html#method.ipv4_gateway
pub fn ipv4_gateway<T>(mut self, gateway: T) -> InterfaceBuilder<'b, 'c, DeviceT>
where T: Into<Ipv4Address> {
let addr = gateway.into();
InterfaceInner::check_gateway_addr(&addr);
self.ipv4_gateway = Some(addr);
self
}
/// Set the Neighbor Cache the interface will use.
pub fn neighbor_cache(mut self, neighbor_cache: NeighborCache<'b>) -> InterfaceBuilder<'b, 'c, DeviceT> {
self.neighbor_cache = Some(neighbor_cache);
self
}
/// Create a network interface using the previously provided configuration.
///
/// # Panics
/// If a required option is not provided, this function will panic. Required
/// options are:
///
/// - [ethernet_addr]
/// - [neighbor_cache]
/// - [ip_addrs]
///
/// [ethernet_addr]: #method.ethernet_addr
/// [neighbor_cache]: #method.neighbor_cache
/// [ip_addrs]: #method.ip_addrs
pub fn finalize(self) -> Interface<'b, 'c, DeviceT> {
// TODO: Limit the number of required options.
match (self.ethernet_addr, self.neighbor_cache, self.ip_addrs) {
(Some(ethernet_addr), Some(neighbor_cache), Some(ip_addrs)) => {
let device_capabilities = self.device.capabilities();
Interface {
device: self.device,
inner: InterfaceInner {
ethernet_addr, device_capabilities, neighbor_cache,
ip_addrs, ipv4_gateway: self.ipv4_gateway,
}
}
},
_ => panic!("a required option was not set"),
}
}
}
#[derive(Debug, PartialEq)]
enum Packet<'a> {
None,
@ -84,33 +210,6 @@ impl<'a> Packet<'a> {
impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
where DeviceT: for<'d> Device<'d> {
/// Create a network interface using the provided network device.
///
/// # Panics
/// See the restrictions on [set_hardware_addr](#method.set_hardware_addr)
/// and [set_protocol_addrs](#method.set_protocol_addrs) functions.
pub fn new<ProtocolAddrsMT, Ipv4GatewayAddrT>
(device: DeviceT,
neighbor_cache: NeighborCache<'b>,
ethernet_addr: EthernetAddress,
ip_addrs: ProtocolAddrsMT,
ipv4_gateway: Ipv4GatewayAddrT) ->
Interface<'b, 'c, DeviceT>
where ProtocolAddrsMT: Into<ManagedSlice<'c, IpCidr>>,
Ipv4GatewayAddrT: Into<Option<Ipv4Address>>, {
let ip_addrs = ip_addrs.into();
InterfaceInner::check_ethernet_addr(&ethernet_addr);
InterfaceInner::check_ip_addrs(&ip_addrs);
let inner = InterfaceInner {
ethernet_addr, ip_addrs, neighbor_cache,
ipv4_gateway: ipv4_gateway.into(),
device_capabilities: device.capabilities(),
};
Interface { device, inner }
}
/// Get the Ethernet address of the interface.
pub fn ethernet_addr(&self) -> EthernetAddress {
self.inner.ethernet_addr
@ -314,6 +413,12 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
}
}
fn check_gateway_addr(addr: &Ipv4Address) {
if !addr.is_unicast() {
panic!("gateway IP address {} is not unicast", addr);
}
}
/// Check whether the interface has the given IP address assigned.
fn has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
let addr = addr.into();
@ -795,6 +900,7 @@ mod test {
use std::collections::BTreeMap;
use {Result, Error};
use super::InterfaceBuilder;
use iface::{NeighborCache, EthernetInterface};
use phy::{self, Loopback, ChecksumCapabilities};
use socket::SocketSet;
@ -812,12 +918,13 @@ mod test {
// Create a basic device
let device = Loopback::new();
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let iface = InterfaceBuilder::new(device)
.ethernet_addr(EthernetAddress::default())
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
.ip_addrs([IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8)])
.finalize();
let ip_addr = IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8);
(EthernetInterface::new(device, neighbor_cache,
EthernetAddress::default(), [ip_addr], None),
SocketSet::new(vec![]))
(iface, SocketSet::new(vec![]))
}
#[derive(Debug, PartialEq)]
@ -830,6 +937,12 @@ mod test {
}
}
#[test]
#[should_panic(expected = "a required option was not set")]
fn test_builder_initialization_panic() {
InterfaceBuilder::new(Loopback::new()).finalize();
}
#[test]
fn test_no_icmp_to_broadcast() {
let (mut iface, mut socket_set) = create_loopback();

View File

@ -9,4 +9,5 @@ mod ethernet;
pub use self::neighbor::Neighbor as Neighbor;
pub(crate) use self::neighbor::Answer as NeighborAnswer;
pub use self::neighbor::Cache as NeighborCache;
pub use self::ethernet::Interface as EthernetInterface;
pub use self::ethernet::{Interface as EthernetInterface,
InterfaceBuilder as EthernetInterfaceBuilder};