From f6b6faf50a7f8f1c828f6b41d1fbd26f3c107e6b Mon Sep 17 00:00:00 2001 From: Dennis Schwerdel Date: Wed, 25 Nov 2015 19:23:25 +0100 Subject: [PATCH] Performance measurements --- Measurements_Glab.ods | Bin 42658 -> 0 bytes README.md | 2 + performance.md | 91 ++++++++++++++++++++++++++++++++++++++++++ src/ethernet.rs | 22 +++++----- src/ip.rs | 2 +- src/types.rs | 2 +- 6 files changed, 107 insertions(+), 12 deletions(-) delete mode 100644 Measurements_Glab.ods create mode 100644 performance.md diff --git a/Measurements_Glab.ods b/Measurements_Glab.ods deleted file mode 100644 index eb98e1296f4f7369c666952d211cb54cfc059284..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42658 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 ./vpncloud -t tap -l NODE1:3210 -c NODE2:3210 \ + --ifup 'ifconfig $IFNAME 10.2.1.1/24 mtu MTU up' & +``` + +Node 2: +``` +$> ./vpncloud -t tap -l NODE2:3210 -c NODE1:3210 \ + --ifup 'ifconfig $IFNAME 10.2.1.2/24 mtu MTU up' & +$> iperf -s & +$> top +``` + +First, the test is run **without VpnCloud**: +``` +$> iperf -c NODE2 -t 60 +``` + +and then **via VpnCloud**: +``` +$> iperf -c 10.2.1.2 -t 60 +``` + +**Results:** + * Throughput without VpnCloud: 938 Mbits/sec + * Throughput via VpnCloud (MTU=1400): 363 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 + + +### Test 2: Unencrypted ping + +Node 1: +``` +$> ./vpncloud -t tap -l NODE1:3210 -c NODE2:3210 \ + --ifup 'ifconfig $IFNAME 10.2.1.1/24 mtu 1400 up' & +``` + +Node 2: +``` +$> ./vpncloud -t tap -l NODE2:3210 -c NODE1:3210 \ + --ifup 'ifconfig $IFNAME 10.2.1.2/24 mtu 1400 up' & +``` + +Each test is first run without VpnCloud: +``` +$> ping NODE2 -c 1000 -i 0.01 -s SIZE -U -q +``` + +and then with VpnCloud: +``` +$> ping 10.2.1.2 -c 1000 -i 0.01 -s SIZE -U -q +``` + +SIZE: 50 bytes + * Without VpnCloud: Ø= 200 µs, stddev= 28 µs + * With VpnCloud: Ø= 318 µs, stddev= 26 µs + +SIZE: 500 bytes + * Without VpnCloud: Ø= 235 µs, stddev= 29 µs + * With VpnCloud: Ø= 351 µs, stddev= 26 µs + +SIZE: 1400 bytes + * Without VpnCloud: Ø= 303 µs, stddev= 32 µs + * With VpnCloud: Ø= 421 µs, stddev= 31 µs + + +### Conclusion + +* VpnCloud achieves about 360 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. diff --git a/src/ethernet.rs b/src/ethernet.rs index 22b5472..73aeb65 100644 --- a/src/ethernet.rs +++ b/src/ethernet.rs @@ -58,12 +58,13 @@ struct SwitchTableValue { pub struct SwitchTable { table: HashMap, + cache: Option<(Address, SocketAddr)>, timeout: Duration } impl SwitchTable { pub fn new(timeout: Duration) -> Self { - SwitchTable{table: HashMap::new(), timeout: timeout} + SwitchTable{table: HashMap::new(), cache: None, timeout: timeout} } } @@ -80,20 +81,21 @@ impl Table for SwitchTable { info!("Forgot address {:?}", key); self.table.remove(&key); } + self.cache = None; } fn learn(&mut self, key: Address, _prefix_len: Option, addr: SocketAddr) { - let value = SwitchTableValue{address: addr, timeout: SteadyTime::now()+self.timeout}; - if self.table.insert(key.clone(), value).is_none() { - info!("Learned address {:?} => {}", key, addr); - } + let value = SwitchTableValue{address: addr, timeout: SteadyTime::now()+self.timeout}; + if self.table.insert(key.clone(), value).is_none() { + info!("Learned address {:?} => {}", key, addr); + } } - fn lookup(&self, key: &Address) -> Option { - match self.table.get(key) { - Some(value) => Some(value.address), - None => None - } + fn lookup(&mut self, key: &Address) -> Option { + match self.table.get(key) { + Some(value) => Some(value.address), + None => None + } } fn remove_all(&mut self, _addr: SocketAddr) { diff --git a/src/ip.rs b/src/ip.rs index 8891532..af0a66c 100644 --- a/src/ip.rs +++ b/src/ip.rs @@ -63,7 +63,7 @@ impl Table for RoutingTable { } } - fn lookup(&self, addr: &Address) -> Option { + fn lookup(&mut self, addr: &Address) -> Option { let len = addr.0.len()/2 * 2; for i in 0..(len/2)+1 { if let Some(group) = self.0.get(&addr.0[0..len-2*i]) { diff --git a/src/types.rs b/src/types.rs index 92014cb..f70fd33 100644 --- a/src/types.rs +++ b/src/types.rs @@ -122,7 +122,7 @@ impl fmt::Display for Mode { pub trait Table { fn learn(&mut self, Address, Option, SocketAddr); - fn lookup(&self, &Address) -> Option; + fn lookup(&mut self, &Address) -> Option; fn housekeep(&mut self); fn remove_all(&mut self, SocketAddr); }