More improvements

This commit is contained in:
Dennis Schwerdel 2015-11-25 21:55:30 +01:00
parent 946e384660
commit ecb57b24de
7 changed files with 57 additions and 35 deletions

View File

@ -12,6 +12,7 @@ log = "0.3"
epoll = "0.2" epoll = "0.2"
signal = "0.1" signal = "0.1"
nix = "*" nix = "*"
libc = "*"
libsodium-sys = {version = "0.0.9", optional = true} libsodium-sys = {version = "0.0.9", optional = true}
[build-dependencies] [build-dependencies]

View File

@ -41,10 +41,10 @@ $> iperf -c 10.2.1.2 -t 60
**Results:** **Results:**
* Throughput without VpnCloud: 938 Mbits/sec * Throughput without VpnCloud: 938 Mbits/sec
* Throughput via VpnCloud (MTU=1400): 363 Mbits/sec * Throughput via VpnCloud (MTU=1400): 461 Mbits/sec
* CPU usage for VpnCloud (MTU=1400): maxed out at ~105% of one core * CPU usage for VpnCloud (MTU=1400): maxed out at ~105% of one core
* Throughput via VpnCloud (MTU=16384): 946 Mbits/sec (no idea why this is higher) * Throughput via VpnCloud (MTU=16384): 949 Mbits/sec (no idea why this is higher)
* CPU usage for VpnCloud (MTU=16384): ~73% of one core * CPU usage for VpnCloud (MTU=16384): ~68% of one core
### Test 2: Unencrypted ping ### Test 2: Unencrypted ping
@ -86,6 +86,6 @@ SIZE: 1400 bytes
### Conclusion ### Conclusion
* VpnCloud achieves about 360 MBit/s with default MTU settings. * VpnCloud achieves about 460 MBit/s with default MTU settings.
* At increased MTU, VpnCloud is able to saturate a Gigabit link. * At increased MTU, VpnCloud is able to saturate a Gigabit link.
* VpnCloud adds about 120µs to the round trip times, i.e. 60µs latency increase. * VpnCloud adds about 120µs to the round trip times, i.e. 60µs latency increase.

View File

@ -1,6 +1,6 @@
use test::Bencher; use test::Bencher;
use time::{SteadyTime, Duration}; use time::Duration;
use std::str::FromStr; use std::str::FromStr;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
@ -61,7 +61,8 @@ fn switch_lookup(b: &mut Bencher) {
#[bench] #[bench]
fn ethernet_parse(b: &mut Bencher) { fn ethernet_parse(b: &mut Bencher) {
let data = [0; 1500]; let mut data = [0; 1500];
data[5] = 45;
b.iter(|| { b.iter(|| {
Frame::parse(&data).unwrap() Frame::parse(&data).unwrap()
}) })

View File

@ -7,19 +7,20 @@ use std::fmt;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::marker::PhantomData; use std::marker::PhantomData;
use time::{Duration, SteadyTime, precise_time_ns};
use epoll; use epoll;
use nix::sys::signal::{SIGTERM, SIGQUIT, SIGINT}; use nix::sys::signal::{SIGTERM, SIGQUIT, SIGINT};
use signal::trap::Trap; use signal::trap::Trap;
use time::SteadyTime;
use super::types::{Table, Protocol, Range, Error, NetworkId}; use super::types::{Table, Protocol, Range, Error, NetworkId};
use super::device::Device; use super::device::Device;
use super::udpmessage::{encode, decode, Options, Message}; use super::udpmessage::{encode, decode, Options, Message};
use super::crypto::Crypto; use super::crypto::Crypto;
use super::util::{now, Time, Duration, time_rand};
struct PeerList { struct PeerList {
timeout: Duration, timeout: Duration,
peers: HashMap<SocketAddr, SteadyTime> peers: HashMap<SocketAddr, Time>
} }
impl PeerList { impl PeerList {
@ -28,7 +29,7 @@ impl PeerList {
} }
fn timeout(&mut self) -> Vec<SocketAddr> { fn timeout(&mut self) -> Vec<SocketAddr> {
let now = SteadyTime::now(); let now = now();
let mut del: Vec<SocketAddr> = Vec::new(); let mut del: Vec<SocketAddr> = Vec::new();
for (&addr, &timeout) in &self.peers { for (&addr, &timeout) in &self.peers {
if timeout < now { if timeout < now {
@ -49,7 +50,7 @@ impl PeerList {
#[inline] #[inline]
fn add(&mut self, addr: &SocketAddr) { fn add(&mut self, addr: &SocketAddr) {
if self.peers.insert(*addr, SteadyTime::now()+self.timeout).is_none() { if self.peers.insert(*addr, now()+self.timeout as Time).is_none() {
info!("New peer: {:?}", addr); info!("New peer: {:?}", addr);
} }
} }
@ -96,10 +97,10 @@ pub struct GenericCloud<P: Protocol> {
device: Device, device: Device,
options: Options, options: Options,
crypto: Crypto, crypto: Crypto,
next_peerlist: SteadyTime, next_peerlist: Time,
update_freq: Duration, update_freq: Duration,
buffer_out: [u8; 64*1024], buffer_out: [u8; 64*1024],
next_housekeep: SteadyTime, next_housekeep: Time,
_dummy_p: PhantomData<P>, _dummy_p: PhantomData<P>,
} }
@ -124,10 +125,10 @@ impl<P: Protocol> GenericCloud<P> {
device: device, device: device,
options: options, options: options,
crypto: crypto, crypto: crypto,
next_peerlist: SteadyTime::now(), next_peerlist: now(),
update_freq: peer_timeout/2, update_freq: peer_timeout/2,
buffer_out: [0; 64*1024], buffer_out: [0; 64*1024],
next_housekeep: SteadyTime::now(), next_housekeep: now(),
_dummy_p: PhantomData, _dummy_p: PhantomData,
} }
} }
@ -169,7 +170,7 @@ impl<P: Protocol> GenericCloud<P> {
fn housekeep(&mut self) -> Result<(), Error> { fn housekeep(&mut self) -> Result<(), Error> {
self.peers.timeout(); self.peers.timeout();
self.table.housekeep(); self.table.housekeep();
if self.next_peerlist <= SteadyTime::now() { if self.next_peerlist <= now() {
debug!("Send peer list to all peers"); debug!("Send peer list to all peers");
let mut peer_num = self.peers.len(); let mut peer_num = self.peers.len();
if peer_num > 10 { if peer_num > 10 {
@ -178,12 +179,12 @@ impl<P: Protocol> GenericCloud<P> {
peer_num = 10; peer_num = 10;
} }
} }
let peers = self.peers.subset(peer_num, precise_time_ns() as u32); let peers = self.peers.subset(peer_num, time_rand() as u32);
let msg = Message::Peers(peers); let msg = Message::Peers(peers);
for addr in &self.peers.as_vec() { for addr in &self.peers.as_vec() {
try!(self.send_msg(addr, &msg)); try!(self.send_msg(addr, &msg));
} }
self.next_peerlist = SteadyTime::now() + self.update_freq; self.next_peerlist = now() + self.update_freq as Time;
} }
for addr in self.reconnect_peers.clone() { for addr in self.reconnect_peers.clone() {
try!(self.connect(addr, false)); try!(self.connect(addr, false));
@ -272,6 +273,7 @@ impl<P: Protocol> GenericCloud<P> {
} }
pub fn run(&mut self) { pub fn run(&mut self) {
let dummy_time = SteadyTime::now();
let trap = Trap::trap(&[SIGINT, SIGTERM, SIGQUIT]); let trap = Trap::trap(&[SIGINT, SIGTERM, SIGQUIT]);
let epoll_handle = try_fail!(epoll::create1(0), "Failed to create epoll handle: {}"); let epoll_handle = try_fail!(epoll::create1(0), "Failed to create epoll handle: {}");
let socket_fd = self.socket.as_raw_fd(); let socket_fd = self.socket.as_raw_fd();
@ -284,10 +286,6 @@ impl<P: Protocol> GenericCloud<P> {
let mut buffer = [0; 64*1024]; let mut buffer = [0; 64*1024];
loop { loop {
let count = try_fail!(epoll::wait(epoll_handle, &mut events, 1000), "Epoll wait failed: {}"); let count = try_fail!(epoll::wait(epoll_handle, &mut events, 1000), "Epoll wait failed: {}");
// Check for signals
if trap.wait(SteadyTime::now()).is_some() {
break;
}
// Process events // Process events
for i in 0..count { for i in 0..count {
match &events[i as usize].data { match &events[i as usize].data {
@ -308,13 +306,17 @@ impl<P: Protocol> GenericCloud<P> {
_ => unreachable!() _ => unreachable!()
} }
} }
// Do the housekeeping if self.next_housekeep < now() {
if self.next_housekeep < SteadyTime::now() { // Check for signals
if trap.wait(dummy_time).is_some() {
break;
}
// Do the housekeeping
match self.housekeep() { match self.housekeep() {
Ok(_) => (), Ok(_) => (),
Err(e) => error!("Error: {:?}", e) Err(e) => error!("Error: {:?}", e)
} }
self.next_housekeep = SteadyTime::now() + Duration::seconds(1) self.next_housekeep = now() + 1
} }
} }
info!("Shutting down..."); info!("Shutting down...");

View File

@ -3,9 +3,7 @@ use std::net::SocketAddr;
use std::collections::HashMap; use std::collections::HashMap;
use super::types::{Error, Table, Protocol, Address}; use super::types::{Error, Table, Protocol, Address};
use super::util::{now, Time, Duration};
use time::{Duration, SteadyTime};
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct Frame; pub struct Frame;
@ -49,7 +47,7 @@ impl Protocol for Frame {
struct SwitchTableValue { struct SwitchTableValue {
address: SocketAddr, address: SocketAddr,
timeout: SteadyTime timeout: Time
} }
pub struct SwitchTable { pub struct SwitchTable {
@ -66,7 +64,7 @@ impl SwitchTable {
impl Table for SwitchTable { impl Table for SwitchTable {
fn housekeep(&mut self) { fn housekeep(&mut self) {
let now = SteadyTime::now(); let now = now();
let mut del: Vec<Address> = Vec::new(); let mut del: Vec<Address> = Vec::new();
for (key, val) in &self.table { for (key, val) in &self.table {
if val.timeout < now { if val.timeout < now {
@ -82,7 +80,7 @@ impl Table for SwitchTable {
#[inline] #[inline]
fn learn(&mut self, key: Address, _prefix_len: Option<u8>, addr: SocketAddr) { fn learn(&mut self, key: Address, _prefix_len: Option<u8>, addr: SocketAddr) {
let value = SwitchTableValue{address: addr, timeout: SteadyTime::now()+self.timeout}; let value = SwitchTableValue{address: addr, timeout: now()+self.timeout as Time};
if self.table.insert(key.clone(), value).is_none() { if self.table.insert(key.clone(), value).is_none() {
info!("Learned address {:?} => {}", key, addr); info!("Learned address {:?} => {}", key, addr);
} }

View File

@ -6,6 +6,7 @@ extern crate rustc_serialize;
extern crate epoll; extern crate epoll;
extern crate signal; extern crate signal;
extern crate nix; extern crate nix;
extern crate libc;
#[cfg(feature = "crypto")] extern crate libsodium_sys; #[cfg(feature = "crypto")] extern crate libsodium_sys;
#[cfg(feature = "bench")] extern crate test; #[cfg(feature = "bench")] extern crate test;
@ -19,7 +20,6 @@ mod cloud;
mod device; mod device;
#[cfg(feature = "bench")] mod benches; #[cfg(feature = "bench")] mod benches;
use time::Duration;
use docopt::Docopt; use docopt::Docopt;
use std::hash::{Hash, SipHasher, Hasher}; use std::hash::{Hash, SipHasher, Hasher};
@ -33,6 +33,7 @@ use types::{Error, Mode, Type, Range, Table, Protocol};
use cloud::GenericCloud; use cloud::GenericCloud;
use udpmessage::VERSION; use udpmessage::VERSION;
use crypto::Crypto; use crypto::Crypto;
use util::Duration;
struct SimpleLogger; struct SimpleLogger;
@ -63,8 +64,8 @@ struct Args {
flag_listen: String, flag_listen: String,
flag_network_id: Option<String>, flag_network_id: Option<String>,
flag_connect: Vec<String>, flag_connect: Vec<String>,
flag_peer_timeout: usize, flag_peer_timeout: Duration,
flag_dst_timeout: usize, flag_dst_timeout: Duration,
flag_verbose: bool, flag_verbose: bool,
flag_quiet: bool, flag_quiet: bool,
flag_ifup: Option<String>, flag_ifup: Option<String>,
@ -93,8 +94,8 @@ fn run<T: Protocol> (args: Args) {
for s in args.flag_subnet { for s in args.flag_subnet {
ranges.push(try_fail!(Range::from_str(&s), "Invalid subnet format: {} ({})", s)); ranges.push(try_fail!(Range::from_str(&s), "Invalid subnet format: {} ({})", s));
} }
let dst_timeout = Duration::seconds(args.flag_dst_timeout as i64); let dst_timeout = args.flag_dst_timeout;
let peer_timeout = Duration::seconds(args.flag_peer_timeout as i64); let peer_timeout = args.flag_peer_timeout;
let (learning, broadcasting, table): (bool, bool, Box<Table>) = match args.flag_mode { let (learning, broadcasting, table): (bool, bool, Box<Table>) = match args.flag_mode {
Mode::Normal => match args.flag_type { Mode::Normal => match args.flag_type {
Type::Tap => (true, true, Box::new(SwitchTable::new(dst_timeout))), Type::Tap => (true, true, Box::new(SwitchTable::new(dst_timeout))),

View File

@ -1,4 +1,23 @@
use std::{mem, slice}; use std::{mem, slice};
use libc;
pub type Duration = u32;
pub type Time = i64;
#[inline]
pub fn now() -> Time {
let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
unsafe { libc::clock_gettime(6, &mut tv); }
tv.tv_sec
}
#[inline]
pub fn time_rand() -> i64 {
let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut tv); }
tv.tv_sec ^ tv.tv_nsec
}
#[inline(always)] #[inline(always)]
pub unsafe fn as_bytes<T>(obj: &T) -> &[u8] { pub unsafe fn as_bytes<T>(obj: &T) -> &[u8] {