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"
signal = "0.1"
nix = "*"
libc = "*"
libsodium-sys = {version = "0.0.9", optional = true}
[build-dependencies]

View File

@ -41,10 +41,10 @@ $> iperf -c 10.2.1.2 -t 60
**Results:**
* 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
* Throughput via VpnCloud (MTU=16384): 946 Mbits/sec (no idea why this is higher)
* CPU usage for VpnCloud (MTU=16384): ~73% of one core
* Throughput via VpnCloud (MTU=16384): 949 Mbits/sec (no idea why this is higher)
* CPU usage for VpnCloud (MTU=16384): ~68% of one core
### Test 2: Unencrypted ping
@ -86,6 +86,6 @@ SIZE: 1400 bytes
### 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.
* 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 time::{SteadyTime, Duration};
use time::Duration;
use std::str::FromStr;
use std::net::ToSocketAddrs;
@ -61,7 +61,8 @@ fn switch_lookup(b: &mut Bencher) {
#[bench]
fn ethernet_parse(b: &mut Bencher) {
let data = [0; 1500];
let mut data = [0; 1500];
data[5] = 45;
b.iter(|| {
Frame::parse(&data).unwrap()
})

View File

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

View File

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

View File

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

View File

@ -1,4 +1,23 @@
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)]
pub unsafe fn as_bytes<T>(obj: &T) -> &[u8] {