2015-11-22 23:49:58 +00:00
|
|
|
use std::ptr;
|
2015-11-21 15:50:50 +00:00
|
|
|
use std::net::SocketAddr;
|
|
|
|
use std::collections::HashMap;
|
2015-11-19 15:34:20 +00:00
|
|
|
|
2015-11-23 00:04:30 +00:00
|
|
|
use super::types::{Error, Table, Protocol, Address};
|
2015-11-19 15:34:20 +00:00
|
|
|
|
2015-11-21 15:50:50 +00:00
|
|
|
use time::{Duration, SteadyTime};
|
|
|
|
|
2015-11-22 16:28:04 +00:00
|
|
|
|
2015-11-19 15:34:20 +00:00
|
|
|
#[derive(PartialEq)]
|
2015-11-22 17:05:15 +00:00
|
|
|
pub struct Frame;
|
2015-11-21 17:09:13 +00:00
|
|
|
|
2015-11-22 17:05:15 +00:00
|
|
|
impl Protocol for Frame {
|
2015-11-22 23:49:58 +00:00
|
|
|
fn parse(data: &[u8]) -> Result<(Address, Address), Error> {
|
2015-11-22 15:48:01 +00:00
|
|
|
if data.len() < 14 {
|
|
|
|
return Err(Error::ParseError("Frame is too short"));
|
|
|
|
}
|
|
|
|
let mut pos = 0;
|
2015-11-22 23:49:58 +00:00
|
|
|
let dst_data = &data[pos..pos+6];
|
|
|
|
pos += 6;
|
|
|
|
let src_data = &data[pos..pos+6];
|
|
|
|
pos += 6;
|
2015-11-22 15:48:01 +00:00
|
|
|
if data[pos] == 0x81 && data[pos+1] == 0x00 {
|
|
|
|
pos += 2;
|
|
|
|
if data.len() < pos + 2 {
|
|
|
|
return Err(Error::ParseError("Vlan frame is too short"));
|
|
|
|
}
|
2015-11-25 20:05:11 +00:00
|
|
|
let mut src = [0; 16];
|
|
|
|
let mut dst = [0; 16];
|
2015-11-22 23:49:58 +00:00
|
|
|
unsafe {
|
2015-11-23 00:00:18 +00:00
|
|
|
ptr::copy_nonoverlapping(data[pos..].as_ptr(), src.as_mut_ptr(), 2);
|
|
|
|
ptr::copy_nonoverlapping(src_data.as_ptr(), src[2..].as_mut_ptr(), 6);
|
|
|
|
ptr::copy_nonoverlapping(data[pos..].as_ptr(), dst.as_mut_ptr(), 2);
|
|
|
|
ptr::copy_nonoverlapping(dst_data.as_ptr(), dst[2..].as_mut_ptr(), 6);
|
2015-11-22 23:49:58 +00:00
|
|
|
}
|
2015-11-25 20:05:11 +00:00
|
|
|
Ok((Address(src, 8), Address(dst, 8)))
|
2015-11-22 23:49:58 +00:00
|
|
|
} else {
|
2015-11-25 20:05:11 +00:00
|
|
|
let mut src = [0; 16];
|
|
|
|
let mut dst = [0; 16];
|
2015-11-22 23:49:58 +00:00
|
|
|
unsafe {
|
|
|
|
ptr::copy_nonoverlapping(src_data.as_ptr(), src.as_mut_ptr(), 6);
|
|
|
|
ptr::copy_nonoverlapping(dst_data.as_ptr(), dst.as_mut_ptr(), 6);
|
|
|
|
}
|
2015-11-25 20:05:11 +00:00
|
|
|
Ok((Address(src, 6), Address(dst, 6)))
|
2015-11-22 15:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-22 16:28:04 +00:00
|
|
|
|
2015-11-23 00:40:47 +00:00
|
|
|
struct SwitchTableValue {
|
2015-11-21 15:50:50 +00:00
|
|
|
address: SocketAddr,
|
|
|
|
timeout: SteadyTime
|
|
|
|
}
|
|
|
|
|
2015-11-23 00:40:47 +00:00
|
|
|
pub struct SwitchTable {
|
|
|
|
table: HashMap<Address, SwitchTableValue>,
|
2015-11-25 18:23:25 +00:00
|
|
|
cache: Option<(Address, SocketAddr)>,
|
2015-11-21 15:50:50 +00:00
|
|
|
timeout: Duration
|
|
|
|
}
|
|
|
|
|
2015-11-23 00:40:47 +00:00
|
|
|
impl SwitchTable {
|
|
|
|
pub fn new(timeout: Duration) -> Self {
|
2015-11-25 18:23:25 +00:00
|
|
|
SwitchTable{table: HashMap::new(), cache: None, timeout: timeout}
|
2015-11-21 15:50:50 +00:00
|
|
|
}
|
2015-11-21 17:09:13 +00:00
|
|
|
}
|
|
|
|
|
2015-11-23 00:40:47 +00:00
|
|
|
impl Table for SwitchTable {
|
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-22 23:49:58 +00:00
|
|
|
let mut del: Vec<Address> = Vec::new();
|
|
|
|
for (key, val) in &self.table {
|
2015-11-21 15:50:50 +00:00
|
|
|
if val.timeout < now {
|
2015-11-22 23:49:58 +00:00
|
|
|
del.push(key.clone());
|
2015-11-21 15:50:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for key in del {
|
2015-11-22 23:49:58 +00:00
|
|
|
info!("Forgot address {:?}", key);
|
2015-11-21 15:50:50 +00:00
|
|
|
self.table.remove(&key);
|
|
|
|
}
|
2015-11-25 18:23:25 +00:00
|
|
|
self.cache = None;
|
2015-11-21 15:50:50 +00:00
|
|
|
}
|
|
|
|
|
2015-11-25 20:05:11 +00:00
|
|
|
#[inline]
|
2015-11-22 23:49:58 +00:00
|
|
|
fn learn(&mut self, key: Address, _prefix_len: Option<u8>, addr: SocketAddr) {
|
2015-11-25 18:23:25 +00:00
|
|
|
let value = SwitchTableValue{address: addr, timeout: SteadyTime::now()+self.timeout};
|
|
|
|
if self.table.insert(key.clone(), value).is_none() {
|
|
|
|
info!("Learned address {:?} => {}", key, addr);
|
|
|
|
}
|
2015-11-21 15:50:50 +00:00
|
|
|
}
|
|
|
|
|
2015-11-25 20:05:11 +00:00
|
|
|
#[inline]
|
2015-11-25 18:23:25 +00:00
|
|
|
fn lookup(&mut self, key: &Address) -> Option<SocketAddr> {
|
|
|
|
match self.table.get(key) {
|
|
|
|
Some(value) => Some(value.address),
|
|
|
|
None => None
|
|
|
|
}
|
2015-11-21 15:50:50 +00:00
|
|
|
}
|
2015-11-22 21:00:34 +00:00
|
|
|
|
|
|
|
fn remove_all(&mut self, _addr: SocketAddr) {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
2015-11-21 15:50:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-19 15:34:20 +00:00
|
|
|
#[test]
|
|
|
|
fn without_vlan() {
|
2015-11-22 17:05:15 +00:00
|
|
|
let data = [6,5,4,3,2,1,1,2,3,4,5,6,1,2,3,4,5,6,7,8];
|
|
|
|
let (src, dst) = Frame::parse(&data).unwrap();
|
2015-11-25 20:05:11 +00:00
|
|
|
assert_eq!(src, Address([1,2,3,4,5,6,0,0,0,0,0,0,0,0,0,0], 6));
|
|
|
|
assert_eq!(dst, Address([6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 6));
|
2015-11-19 15:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn with_vlan() {
|
2015-11-22 17:05:15 +00:00
|
|
|
let data = [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 (src, dst) = Frame::parse(&data).unwrap();
|
2015-11-25 20:05:11 +00:00
|
|
|
assert_eq!(src, Address([4,210,1,2,3,4,5,6,0,0,0,0,0,0,0,0], 8));
|
|
|
|
assert_eq!(dst, Address([4,210,6,5,4,3,2,1,0,0,0,0,0,0,0,0], 8));
|
2015-11-19 15:34:20 +00:00
|
|
|
}
|