Support for loopback interface.

This commit is contained in:
Egor Karavaev
2017-10-24 22:23:03 +03:00
parent 7f7109b218
commit b54ead7d77
5 changed files with 113 additions and 18 deletions
+45
View File
@@ -0,0 +1,45 @@
use smoltcp::iface::{ArpCache, SliceArpCache};
use smoltcp::wire::{EthernetAddress, IpAddress};
use std::collections::BTreeSet;
use std::iter::FromIterator;
//TODO: move to EthernetAddress::LOCAL (?)
pub const LOOPBACK_HWADDR: EthernetAddress = EthernetAddress([0; 6]);
pub struct LoArpCache {
arp_cache: SliceArpCache<'static>,
local_ips: BTreeSet<IpAddress>,
}
impl LoArpCache {
pub fn new<I>(local_ips: I) -> LoArpCache
where
I: IntoIterator<Item = IpAddress>,
{
LoArpCache {
arp_cache: SliceArpCache::new(vec![Default::default(); 16]),
local_ips: BTreeSet::from_iter(local_ips),
}
}
}
impl ArpCache for LoArpCache {
fn fill(&mut self, protocol_addr: &IpAddress, hardware_addr: &EthernetAddress) {
self.arp_cache.fill(protocol_addr, hardware_addr)
}
fn lookup(&mut self, protocol_addr: &IpAddress) -> Option<EthernetAddress> {
//TODO: use IpAddress::is_loopback
if let &IpAddress::Ipv4(ipv4_addr) = protocol_addr {
if ipv4_addr.is_loopback() {
return Some(LOOPBACK_HWADDR);
}
}
if self.local_ips.contains(protocol_addr) {
return Some(LOOPBACK_HWADDR);
}
self.arp_cache.lookup(protocol_addr)
}
}
+15 -6
View File
@@ -1,7 +1,7 @@
use std::ops::{Deref, DerefMut, Drop};
use std::rc::Rc;
use std::cell::RefCell;
use std::mem::swap;
use std::mem::{replace, swap};
type BufferStack = Rc<RefCell<Vec<Vec<u8>>>>;
@@ -14,6 +14,13 @@ impl Buffer {
pub fn resize(&mut self, new_len: usize) {
self.buffer.resize(new_len, 0u8);
}
pub fn move_out(&mut self) -> Buffer {
Buffer {
buffer: replace(&mut self.buffer, vec![]),
stack: self.stack.clone(),
}
}
}
impl AsRef<[u8]> for Buffer {
@@ -44,11 +51,13 @@ impl DerefMut for Buffer {
impl Drop for Buffer {
fn drop(&mut self) {
let mut tmp = vec![];
swap(&mut tmp, &mut self.buffer);
{
let mut stack = self.stack.borrow_mut();
stack.push(tmp);
if self.buffer.capacity() > 0 {
let mut tmp = vec![];
swap(&mut tmp, &mut self.buffer);
{
let mut stack = self.stack.borrow_mut();
stack.push(tmp);
}
}
}
}
+32 -4
View File
@@ -5,11 +5,14 @@ use std::fs::File;
use std::io::Write;
use std::rc::Rc;
use buffer_pool::Buffer;
use buffer_pool::{Buffer, BufferPool};
use arp_cache::LOOPBACK_HWADDR;
pub struct NetworkDevice {
network_file: Rc<RefCell<File>>,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
local_hwaddr: smoltcp::wire::EthernetAddress,
buffer_pool: Rc<RefCell<BufferPool>>,
}
impl NetworkDevice {
@@ -18,17 +21,23 @@ impl NetworkDevice {
pub fn new(
network_file: Rc<RefCell<File>>,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
local_hwaddr: smoltcp::wire::EthernetAddress,
buffer_pool: Rc<RefCell<BufferPool>>,
) -> NetworkDevice {
NetworkDevice {
network_file,
input_queue,
local_hwaddr,
buffer_pool,
}
}
}
pub struct TxBuffer {
buffer: Vec<u8>,
buffer: Buffer,
network_file: Rc<RefCell<File>>,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
local_hwaddr: smoltcp::wire::EthernetAddress,
}
impl AsRef<[u8]> for TxBuffer {
@@ -45,7 +54,22 @@ impl AsMut<[u8]> for TxBuffer {
impl Drop for TxBuffer {
fn drop(&mut self) {
let _ = self.network_file.borrow_mut().write(&self.buffer);
let mut loopback = false;
if let Ok(mut frame) = smoltcp::wire::EthernetFrame::new_checked(&mut self.buffer) {
if frame.dst_addr() == LOOPBACK_HWADDR {
frame.set_dst_addr(self.local_hwaddr);
loopback = true;
}
}
if loopback {
self.input_queue
.borrow_mut()
.push_back(self.buffer.move_out());
} else {
let _ = self.network_file.borrow_mut().write(&self.buffer);
}
}
}
@@ -68,9 +92,13 @@ impl smoltcp::phy::Device for NetworkDevice {
}
fn transmit(&mut self, _timestamp: u64, length: usize) -> smoltcp::Result<Self::TxBuffer> {
let mut buffer = self.buffer_pool.borrow_mut().get_buffer();
buffer.resize(length);
Ok(TxBuffer {
network_file: Rc::clone(&self.network_file),
buffer: vec![0; length],
buffer,
input_queue: Rc::clone(&self.input_queue),
local_hwaddr: self.local_hwaddr,
})
}
}
+1
View File
@@ -23,6 +23,7 @@ mod error;
mod logger;
mod port_set;
mod scheme;
mod arp_cache;
fn run() -> Result<()> {
use syscall::flag::*;
+20 -8
View File
@@ -1,5 +1,5 @@
use netutils::getcfg;
use smoltcp::iface::{ArpCache, EthernetInterface, SliceArpCache};
use smoltcp::iface::{ArpCache, EthernetInterface};
use smoltcp::socket::SocketSet as SmoltcpSocketSet;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint, Ipv4Address};
use std::cell::RefCell;
@@ -16,6 +16,7 @@ use syscall;
use buffer_pool::{Buffer, BufferPool};
use device::NetworkDevice;
use error::{Error, Result};
use arp_cache::LoArpCache;
use self::ip::IpScheme;
use self::tcp::TcpScheme;
use self::udp::UdpScheme;
@@ -41,11 +42,11 @@ pub struct Smolnetd {
tcp_scheme: TcpScheme,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
input_buffer_pool: BufferPool,
buffer_pool: Rc<RefCell<BufferPool>>,
}
impl Smolnetd {
const INGRESS_PACKET_SIZE: usize = 2048;
const MAX_PACKET_SIZE: usize = 2048;
const SOCKET_BUFFER_SIZE: usize = 128; //packets
const MIN_CHECK_TIMEOUT_MS: i64 = 10;
const MAX_CHECK_TIMEOUT_MS: i64 = 500;
@@ -57,17 +58,28 @@ impl Smolnetd {
tcp_file: File,
time_file: File,
) -> Smolnetd {
let arp_cache = SliceArpCache::new(vec![Default::default(); 8]);
let hardware_addr = EthernetAddress::from_str(getcfg("mac").unwrap().trim())
.expect("Can't parse the 'mac' cfg");
let local_ip =
IpAddress::from_str(getcfg("ip").unwrap().trim()).expect("Can't parse the 'ip' cfg.");
let protocol_addrs = [IpCidr::new(local_ip, 24)];
let protocol_addrs = [
IpCidr::new(local_ip, 24),
IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8),
];
let default_gw = Ipv4Address::from_str(getcfg("ip_router").unwrap().trim())
.expect("Can't parse the 'ip_router' cfg.");
let buffer_pool = Rc::new(RefCell::new(BufferPool::new(Self::MAX_PACKET_SIZE)));
let input_queue = Rc::new(RefCell::new(VecDeque::new()));
let network_file = Rc::new(RefCell::new(network_file));
let network_device = NetworkDevice::new(Rc::clone(&network_file), Rc::clone(&input_queue));
let network_device = NetworkDevice::new(
Rc::clone(&network_file),
Rc::clone(&input_queue),
hardware_addr,
buffer_pool.clone(),
);
let arp_cache = LoArpCache::new(protocol_addrs.iter().map(IpCidr::address));
let iface = EthernetInterface::new(
Box::new(network_device),
Box::new(arp_cache) as Box<ArpCache>,
@@ -86,7 +98,7 @@ impl Smolnetd {
tcp_scheme: TcpScheme::new(Rc::clone(&socket_set), tcp_file),
input_queue,
network_file,
input_buffer_pool: BufferPool::new(Self::INGRESS_PACKET_SIZE),
buffer_pool,
}
}
@@ -173,7 +185,7 @@ impl Smolnetd {
fn read_frames(&mut self) -> Result<usize> {
let mut total_frames = 0;
loop {
let mut buffer = self.input_buffer_pool.get_buffer();
let mut buffer = self.buffer_pool.borrow_mut().get_buffer();
let count = self.network_file
.borrow_mut()
.read(&mut buffer)