2015-11-19 18:29:42 +00:00
|
|
|
use std::{mem, ptr, fmt};
|
2015-11-21 15:50:50 +00:00
|
|
|
use std::net::SocketAddr;
|
|
|
|
use std::collections::HashMap;
|
2015-11-21 17:09:13 +00:00
|
|
|
use std::marker::PhantomData;
|
2015-11-19 15:34:20 +00:00
|
|
|
|
2015-11-21 17:09:13 +00:00
|
|
|
use super::ethcloud::{Error, Table, InterfaceMessage, VirtualInterface};
|
2015-11-19 18:29:42 +00:00
|
|
|
use super::util::{as_bytes, as_obj};
|
2015-11-19 15:34:20 +00:00
|
|
|
|
2015-11-21 15:50:50 +00:00
|
|
|
use time::{Duration, SteadyTime};
|
|
|
|
|
|
|
|
|
2015-11-21 17:09:13 +00:00
|
|
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
|
|
pub struct Mac(pub [u8; 6]);
|
|
|
|
|
|
|
|
impl fmt::Debug for Mac {
|
|
|
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
write!(formatter, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
|
|
|
|
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-20 17:09:51 +00:00
|
|
|
pub type VlanId = u16;
|
|
|
|
|
2015-11-21 17:09:13 +00:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
pub struct EthAddr {
|
|
|
|
pub mac: Mac,
|
|
|
|
pub vlan: VlanId
|
|
|
|
}
|
|
|
|
|
2015-11-19 15:34:20 +00:00
|
|
|
#[derive(PartialEq)]
|
|
|
|
pub struct Frame<'a> {
|
2015-11-21 17:09:13 +00:00
|
|
|
pub src: EthAddr,
|
|
|
|
pub dst: EthAddr,
|
2015-11-19 15:34:20 +00:00
|
|
|
pub payload: &'a [u8]
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> fmt::Debug for Frame<'a> {
|
|
|
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
write!(formatter, "src: {:?}, dst: {:?}, vlan: {}, payload: {} bytes",
|
2015-11-21 17:09:13 +00:00
|
|
|
self.src.mac, self.dst.mac, self.src.vlan, self.payload.len())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> InterfaceMessage for Frame<'a> {
|
|
|
|
type Address = EthAddr;
|
|
|
|
|
|
|
|
fn src(&self) -> Self::Address {
|
|
|
|
self.src
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dst(&self) -> Self::Address {
|
|
|
|
self.dst
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct TapDevice<'a>(PhantomData<&'a ()>);
|
|
|
|
|
|
|
|
impl<'a> VirtualInterface for TapDevice<'a> {
|
|
|
|
type Message = Frame<'a>;
|
|
|
|
|
|
|
|
fn read(&mut self) -> Result<Self::Message, Error> {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write(&mut self, msg: Self::Message) -> Result<(), Error> {
|
|
|
|
unimplemented!();
|
2015-11-19 15:34:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn decode(data: &[u8]) -> Result<Frame, Error> {
|
|
|
|
if data.len() < 14 {
|
|
|
|
return Err(Error::ParseError("Frame is too short"));
|
|
|
|
}
|
|
|
|
let mut pos = 0;
|
2015-11-21 17:09:13 +00:00
|
|
|
let dst = *unsafe { as_obj::<Mac>(&data[pos..]) };
|
2015-11-19 15:34:20 +00:00
|
|
|
pos += mem::size_of::<Mac>();
|
2015-11-21 17:09:13 +00:00
|
|
|
let src = *unsafe { as_obj::<Mac>(&data[pos..]) };
|
2015-11-19 15:34:20 +00:00
|
|
|
pos += mem::size_of::<Mac>();
|
|
|
|
let mut vlan = 0;
|
|
|
|
let mut payload = &data[pos..];
|
|
|
|
if data[pos] == 0x81 && data[pos+1] == 0x00 {
|
|
|
|
pos += 2;
|
|
|
|
if data.len() < pos + 2 {
|
|
|
|
return Err(Error::ParseError("Vlan frame is too short"));
|
|
|
|
}
|
|
|
|
vlan = u16::from_be(* unsafe { as_obj::<u16>(&data[pos..]) });
|
|
|
|
pos += 2;
|
|
|
|
payload = &data[pos..];
|
|
|
|
}
|
2015-11-21 17:09:13 +00:00
|
|
|
Ok(Frame{src: EthAddr{mac: src, vlan: vlan}, dst: EthAddr{mac: dst, vlan: vlan}, payload: payload})
|
2015-11-19 15:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn encode(frame: &Frame, buf: &mut [u8]) -> usize {
|
|
|
|
assert!(buf.len() >= 16 + frame.payload.len());
|
|
|
|
let mut pos = 0;
|
|
|
|
unsafe {
|
2015-11-21 17:09:13 +00:00
|
|
|
let dst_dat = as_bytes::<Mac>(&frame.dst.mac);
|
2015-11-19 15:34:20 +00:00
|
|
|
ptr::copy_nonoverlapping(dst_dat.as_ptr(), buf[pos..].as_mut_ptr(), dst_dat.len());
|
|
|
|
pos += dst_dat.len();
|
2015-11-21 17:09:13 +00:00
|
|
|
let src_dat = as_bytes::<Mac>(&frame.src.mac);
|
2015-11-19 15:34:20 +00:00
|
|
|
ptr::copy_nonoverlapping(src_dat.as_ptr(), buf[pos..].as_mut_ptr(), src_dat.len());
|
|
|
|
pos += src_dat.len();
|
2015-11-21 17:09:13 +00:00
|
|
|
if frame.src.vlan != 0 {
|
2015-11-19 15:34:20 +00:00
|
|
|
buf[pos] = 0x81; buf[pos+1] = 0x00;
|
|
|
|
pos += 2;
|
2015-11-21 17:09:13 +00:00
|
|
|
let vlan_dat = mem::transmute::<u16, [u8; 2]>(frame.src.vlan.to_be());
|
2015-11-19 15:34:20 +00:00
|
|
|
ptr::copy_nonoverlapping(vlan_dat.as_ptr(), buf[pos..].as_mut_ptr(), vlan_dat.len());
|
|
|
|
pos += vlan_dat.len();
|
|
|
|
}
|
|
|
|
ptr::copy_nonoverlapping(frame.payload.as_ptr(), buf[pos..].as_mut_ptr(), frame.payload.len());
|
|
|
|
}
|
|
|
|
pos += frame.payload.len();
|
|
|
|
pos
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-21 15:50:50 +00:00
|
|
|
struct MacTableValue {
|
|
|
|
address: SocketAddr,
|
|
|
|
timeout: SteadyTime
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct MacTable {
|
2015-11-21 17:09:13 +00:00
|
|
|
table: HashMap<EthAddr, MacTableValue>,
|
2015-11-21 15:50:50 +00:00
|
|
|
timeout: Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MacTable {
|
|
|
|
pub fn new(timeout: Duration) -> MacTable {
|
|
|
|
MacTable{table: HashMap::new(), timeout: timeout}
|
|
|
|
}
|
2015-11-21 17:09:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Table for MacTable {
|
|
|
|
type Address = EthAddr;
|
2015-11-21 15:50:50 +00:00
|
|
|
|
2015-11-21 17:09:13 +00:00
|
|
|
fn housekeep(&mut self) {
|
2015-11-21 15:50:50 +00:00
|
|
|
let now = SteadyTime::now();
|
2015-11-21 17:09:13 +00:00
|
|
|
let mut del: Vec<Self::Address> = Vec::new();
|
2015-11-21 15:50:50 +00:00
|
|
|
for (&key, val) in &self.table {
|
|
|
|
if val.timeout < now {
|
|
|
|
del.push(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for key in del {
|
|
|
|
info!("Forgot mac: {:?} (vlan {})", key.mac, key.vlan);
|
|
|
|
self.table.remove(&key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-21 17:09:13 +00:00
|
|
|
fn learn(&mut self, key: Self::Address, addr: SocketAddr) {
|
|
|
|
let value = MacTableValue{address: addr, timeout: SteadyTime::now()+self.timeout};
|
2015-11-21 15:50:50 +00:00
|
|
|
if self.table.insert(key, value).is_none() {
|
2015-11-21 17:09:13 +00:00
|
|
|
info!("Learned mac: {:?} (vlan {}) => {}", key.mac, key.vlan, addr);
|
2015-11-21 15:50:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-21 17:09:13 +00:00
|
|
|
fn lookup(&self, key: Self::Address) -> Option<SocketAddr> {
|
2015-11-21 15:50:50 +00:00
|
|
|
match self.table.get(&key) {
|
|
|
|
Some(value) => Some(value.address),
|
|
|
|
None => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-19 15:34:20 +00:00
|
|
|
#[test]
|
|
|
|
fn without_vlan() {
|
|
|
|
let src = Mac([1,2,3,4,5,6]);
|
|
|
|
let dst = Mac([6,5,4,3,2,1]);
|
|
|
|
let payload = [1,2,3,4,5,6,7,8];
|
|
|
|
let mut buf = [0u8; 1024];
|
2015-11-21 17:09:13 +00:00
|
|
|
let frame = Frame{src: EthAddr{mac: src, vlan: 0}, dst: EthAddr{mac: dst, vlan: 0}, payload: &payload};
|
2015-11-19 15:34:20 +00:00
|
|
|
let size = encode(&frame, &mut buf);
|
|
|
|
assert_eq!(size, 20);
|
|
|
|
assert_eq!(&buf[..size], &[6,5,4,3,2,1,1,2,3,4,5,6,1,2,3,4,5,6,7,8]);
|
|
|
|
let frame2 = decode(&buf[..size]).unwrap();
|
|
|
|
assert_eq!(frame, frame2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn with_vlan() {
|
|
|
|
let src = Mac([1,2,3,4,5,6]);
|
|
|
|
let dst = Mac([6,5,4,3,2,1]);
|
|
|
|
let payload = [1,2,3,4,5,6,7,8];
|
|
|
|
let mut buf = [0u8; 1024];
|
2015-11-21 17:09:13 +00:00
|
|
|
let frame = Frame{src: EthAddr{mac: src, vlan: 0}, dst: EthAddr{mac: dst, vlan: 0}, payload: &payload};
|
2015-11-19 15:34:20 +00:00
|
|
|
let size = encode(&frame, &mut buf);
|
|
|
|
assert_eq!(size, 24);
|
|
|
|
assert_eq!(&buf[..size], &[6,5,4,3,2,1,1,2,3,4,5,6,0x81,0,4,210,1,2,3,4,5,6,7,8]);
|
|
|
|
let frame2 = decode(&buf[..size]).unwrap();
|
|
|
|
assert_eq!(frame, frame2);
|
|
|
|
}
|