mirror of https://github.com/dswd/vpncloud.git
More improvements
This commit is contained in:
parent
946e384660
commit
ecb57b24de
|
@ -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]
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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()
|
||||||
})
|
})
|
||||||
|
|
38
src/cloud.rs
38
src/cloud.rs
|
@ -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...");
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -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))),
|
||||||
|
|
19
src/util.rs
19
src/util.rs
|
@ -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] {
|
||||||
|
|
Loading…
Reference in New Issue