diff --git a/src/ethcloud.rs b/src/ethcloud.rs index 620faf7..7488d7b 100644 --- a/src/ethcloud.rs +++ b/src/ethcloud.rs @@ -11,7 +11,7 @@ use epoll; use super::{ethernet, udpmessage}; use super::udpmessage::{Options, Message}; -use super::ethernet::VlanId; +use super::ethernet::MacTable; use super::tapdev::TapDevice; @@ -104,60 +104,6 @@ impl PeerList { } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -struct MacTableKey { - mac: Mac, - vlan: VlanId -} - -struct MacTableValue { - address: SocketAddr, - timeout: SteadyTime -} - -struct MacTable { - table: HashMap, - timeout: Duration -} - -impl MacTable { - fn new(timeout: Duration) -> MacTable { - MacTable{table: HashMap::new(), timeout: timeout} - } - - fn timeout(&mut self) { - let now = SteadyTime::now(); - let mut del: Vec = Vec::new(); - 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); - } - } - - #[inline] - fn learn(&mut self, mac: &Mac, vlan: VlanId, addr: &SocketAddr) { - let key = MacTableKey{mac: *mac, vlan: vlan}; - let value = MacTableValue{address: *addr, timeout: SteadyTime::now()+self.timeout}; - if self.table.insert(key, value).is_none() { - info!("Learned mac: {:?} (vlan {}) => {}", mac, vlan, addr); - } - } - - #[inline] - fn lookup(&self, mac: &Mac, vlan: VlanId) -> Option { - let key = MacTableKey{mac: *mac, vlan: vlan}; - match self.table.get(&key) { - Some(value) => Some(value.address), - None => None - } - } -} - pub struct EthCloud { peers: PeerList, reconnect_peers: Vec, diff --git a/src/ethernet.rs b/src/ethernet.rs index 018f686..2660184 100644 --- a/src/ethernet.rs +++ b/src/ethernet.rs @@ -1,8 +1,13 @@ use std::{mem, ptr, fmt}; +use std::net::SocketAddr; +use std::collections::HashMap; use super::ethcloud::{Mac, Error}; use super::util::{as_bytes, as_obj}; +use time::{Duration, SteadyTime}; + + pub type VlanId = u16; #[derive(PartialEq)] @@ -67,6 +72,61 @@ pub fn encode(frame: &Frame, buf: &mut [u8]) -> usize { } +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +struct MacTableKey { + mac: Mac, + vlan: VlanId +} + +struct MacTableValue { + address: SocketAddr, + timeout: SteadyTime +} + +pub struct MacTable { + table: HashMap, + timeout: Duration +} + +impl MacTable { + pub fn new(timeout: Duration) -> MacTable { + MacTable{table: HashMap::new(), timeout: timeout} + } + + pub fn timeout(&mut self) { + let now = SteadyTime::now(); + let mut del: Vec = Vec::new(); + 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); + } + } + + #[inline] + pub fn learn(&mut self, mac: &Mac, vlan: VlanId, addr: &SocketAddr) { + let key = MacTableKey{mac: *mac, vlan: vlan}; + let value = MacTableValue{address: *addr, timeout: SteadyTime::now()+self.timeout}; + if self.table.insert(key, value).is_none() { + info!("Learned mac: {:?} (vlan {}) => {}", mac, vlan, addr); + } + } + + #[inline] + pub fn lookup(&self, mac: &Mac, vlan: VlanId) -> Option { + let key = MacTableKey{mac: *mac, vlan: vlan}; + match self.table.get(&key) { + Some(value) => Some(value.address), + None => None + } + } +} + + #[test] fn without_vlan() { let src = Mac([1,2,3,4,5,6]); diff --git a/src/ip.rs b/src/ip.rs new file mode 100644 index 0000000..82b464e --- /dev/null +++ b/src/ip.rs @@ -0,0 +1,53 @@ +use std::net::SocketAddr; +use std::collections::{hash_map, HashMap}; + +struct RoutingEntry { + address: SocketAddr, + bytes: Vec, + prefix_len: u8 +} + +pub struct RoutingTable(HashMap, Vec>); + +impl RoutingTable { + pub fn new() -> Self { + RoutingTable(HashMap::new()) + } + + pub fn add(&mut self, bytes: Vec, prefix_len: u8, address: SocketAddr) { + let group_len = (prefix_len as usize / 16) * 2; + let group_bytes: Vec = bytes[..group_len].iter().map(|b| *b).collect(); + let routing_entry = RoutingEntry{address: address, bytes: bytes, prefix_len: prefix_len}; + match self.0.entry(group_bytes) { + hash_map::Entry::Occupied(mut entry) => entry.get_mut().push(routing_entry), + hash_map::Entry::Vacant(entry) => { entry.insert(vec![routing_entry]); () } + } + } + + pub fn lookup(&self, bytes: Vec) -> Option { + let mut len = bytes.len()/2 * 2; + for i in 0..len/2 { + if let Some(group) = self.0.get(&bytes[0..len-2*i]) { + for entry in group { + if entry.bytes.len() != bytes.len() { + continue; + } + let mut match_len = 0; + for i in 0..bytes.len() { + let b = bytes[i] ^ entry.bytes[i]; + if b == 0 { + match_len += 8; + } else { + match_len += b.leading_zeros(); + break; + } + } + if match_len as u8 >= entry.prefix_len { + return Some(entry.address); + } + } + } + } + None + } +} diff --git a/src/main.rs b/src/main.rs index bab77cf..d23403f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ mod util; mod udpmessage; mod tapdev; mod ethernet; +mod ip; mod ethcloud; use time::Duration;