From cb3cc85e38178fcad059e1cb8068dd3c99743134 Mon Sep 17 00:00:00 2001 From: Dennis Schwerdel Date: Fri, 20 Nov 2015 09:49:41 +0100 Subject: [PATCH] Performance improvements --- src/ethcloud.rs | 39 +++++++++++++++++++++++++++++++++++---- src/udpmessage.rs | 27 +++++++++++++-------------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/ethcloud.rs b/src/ethcloud.rs index 4abdc08..5136d30 100644 --- a/src/ethcloud.rs +++ b/src/ethcloud.rs @@ -1,5 +1,5 @@ use std::net::{SocketAddr, ToSocketAddrs}; -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use std::hash::Hasher; use std::net::UdpSocket; use std::io::Read; @@ -141,6 +141,7 @@ pub struct EthCloud { token: Token, next_peerlist: SteadyTime, update_freq: Duration, + cache: VecDeque<(SocketAddr, Mac, u16)>, buffer_out: [u8; 64*1024] } @@ -163,6 +164,7 @@ impl EthCloud { token: token, next_peerlist: SteadyTime::now(), update_freq: peer_timeout/2, + cache: VecDeque::new(), buffer_out: [0; 64*1024] } } @@ -202,7 +204,23 @@ impl EthCloud { fn handle_ethernet_frame(&mut self, frame: ethernet::Frame) -> Result<(), Error> { debug!("Read ethernet frame from tap {:?}", frame); - match self.mactable.lookup(frame.dst, frame.vlan) { + let mut addr = None; + for &(ref peer, ref mac, vlan) in &self.cache { + if mac == frame.dst && vlan == frame.vlan { + addr = Some(*peer); + break; + } + } + if addr.is_none() { + addr = self.mactable.lookup(frame.dst, frame.vlan); + if let Some(addr) = addr { + self.cache.push_front((addr, *frame.dst, frame.vlan)); + if self.cache.len() > 3 { + self.cache.pop_back(); + } + } + } + match addr { Some(addr) => { debug!("Found destination for {:?} (vlan {}) => {}", frame.dst, frame.vlan, addr); try!(self.send_msg(addr, &udpmessage::Message::Frame(frame))) @@ -235,8 +253,21 @@ impl EthCloud { return Err(Error::TapdevError("Failed to write to tap device")); } } - self.peers.add(&peer); - self.mactable.learn(frame.src, frame.vlan, &peer); + let mut in_cache = false; + for &(ref addr, ref mac, vlan) in &self.cache { + if mac == frame.src && vlan == frame.vlan && addr == &peer { + in_cache = true; + break; + } + } + if !in_cache { + self.peers.add(&peer); + self.mactable.learn(frame.src, frame.vlan, &peer); + self.cache.push_front((peer, *frame.src, frame.vlan)); + if self.cache.len() > 3 { + self.cache.pop_back(); + } + } }, udpmessage::Message::Peers(peers) => { self.peers.add(&peer); diff --git a/src/udpmessage.rs b/src/udpmessage.rs index 35b502d..4de7947 100644 --- a/src/udpmessage.rs +++ b/src/udpmessage.rs @@ -38,19 +38,19 @@ impl<'a> fmt::Debug for Message<'a> { } pub fn decode(data: &[u8]) -> Result<(Token, Message), Error> { - if data.len() < 1 + mem::size_of::() { + if data.len() < mem::size_of::() { return Err(Error::ParseError("Empty message")); } let mut pos = 0; - let token = Token::from_be(* unsafe { as_obj::(&data[pos..]) }); + let mut token = Token::from_be(* unsafe { as_obj::(&data[pos..]) }); pos += mem::size_of::(); - match data[pos] { + let switch = token & 0xff; + token = token >> 8; + match switch { 0 => { - pos += 1; Ok((token, Message::Frame(try!(ethernet::decode(&data[pos..]))))) }, 1 => { - pos += 1; if data.len() < pos + 1 { return Err(Error::ParseError("Empty peers")); } @@ -82,20 +82,23 @@ pub fn decode(data: &[u8]) -> Result<(Token, Message), Error> { } pub fn encode(token: Token, msg: &Message, buf: &mut [u8]) -> usize { - assert!(buf.len() >= mem::size_of::() + 1); + assert!(buf.len() >= mem::size_of::()); let mut pos = 0; + let switch = match msg { + &Message::Frame(_) => 0, + &Message::Peers(_) => 1, + &Message::GetPeers => 2, + &Message::Close => 3 + }; + let token = (token << 8) | switch; let token_dat = unsafe { mem::transmute::(token.to_be()) }; unsafe { ptr::copy_nonoverlapping(token_dat.as_ptr(), buf[pos..].as_mut_ptr(), token_dat.len()) }; pos += token_dat.len(); match msg { &Message::Frame(ref frame) => { - buf[pos] = 0; - pos += 1; pos += ethernet::encode(&frame, &mut buf[pos..]) }, &Message::Peers(ref peers) => { - buf[pos] = 1; - pos += 1; let count_pos = pos; pos += 1; assert!(buf.len() >= 2 + peers.len() * mem::size_of::()); @@ -122,12 +125,8 @@ pub fn encode(token: Token, msg: &Message, buf: &mut [u8]) -> usize { pos += 1; }, &Message::GetPeers => { - buf[pos] = 2; - pos += 1; }, &Message::Close => { - buf[pos] = 3; - pos += 1; } } pos