vpncloud/src/traffic.rs

206 lines
6.5 KiB
Rust
Raw Normal View History

2019-02-19 21:04:21 +00:00
// VpnCloud - Peer-to-Peer VPN
2021-02-08 09:11:20 +00:00
// Copyright (C) 2015-2021 Dennis Schwerdel
2019-02-19 21:04:21 +00:00
// This software is licensed under GPL-3 or newer (see LICENSE.md)
2019-12-04 08:32:35 +00:00
use std::{
collections::HashMap,
io::{self, Write},
2020-05-29 09:51:04 +00:00
net::SocketAddr,
2021-04-06 10:28:31 +00:00
ops::AddAssign,
2019-12-04 08:32:35 +00:00
};
2019-01-09 16:45:12 +00:00
2020-05-29 08:04:14 +00:00
use super::{
2020-05-30 14:12:54 +00:00
cloud::{Hash, STATS_INTERVAL},
2020-05-29 08:04:14 +00:00
types::Address,
2021-04-06 10:28:31 +00:00
util::{addr_nice, Bytes},
2020-05-29 08:04:14 +00:00
};
2019-01-09 16:45:12 +00:00
2019-02-14 22:39:16 +00:00
#[derive(Default)]
2019-01-09 16:45:12 +00:00
pub struct TrafficEntry {
pub out_bytes_total: u64,
pub out_packets_total: usize,
pub out_bytes: u64,
pub out_packets: usize,
pub in_bytes_total: u64,
pub in_packets_total: usize,
pub in_bytes: u64,
pub in_packets: usize,
2021-04-06 10:28:31 +00:00
pub idle_periods: usize,
2019-01-09 16:45:12 +00:00
}
2020-05-29 09:51:04 +00:00
impl AddAssign<&TrafficEntry> for TrafficEntry {
fn add_assign(&mut self, other: &TrafficEntry) {
self.out_bytes_total += other.out_bytes_total;
self.out_packets_total += other.out_packets_total;
self.out_bytes += other.out_bytes;
self.out_packets += other.out_packets;
self.in_bytes_total += other.in_bytes_total;
self.in_packets_total += other.in_packets_total;
self.in_bytes += other.in_bytes;
self.in_packets += other.in_packets;
}
}
2019-01-09 16:45:12 +00:00
impl TrafficEntry {
#[inline]
fn count_out(&mut self, bytes: usize) {
self.out_packets += 1;
self.out_bytes += bytes as u64;
}
#[inline]
fn count_in(&mut self, bytes: usize) {
self.in_packets += 1;
self.in_bytes += bytes as u64;
}
fn period(&mut self) {
self.out_bytes_total += self.out_bytes;
self.out_packets_total += self.out_packets;
self.in_bytes_total += self.in_bytes;
self.in_packets_total += self.in_packets;
if self.in_packets == 0 && self.out_packets == 0 {
self.idle_periods += 1;
} else {
self.idle_periods = 0;
}
self.out_packets = 0;
self.in_packets = 0;
self.out_bytes = 0;
self.in_bytes = 0;
}
}
2019-02-14 22:39:16 +00:00
#[derive(Default)]
2019-01-09 16:45:12 +00:00
pub struct TrafficStats {
peers: HashMap<SocketAddr, TrafficEntry, Hash>,
2020-05-29 08:04:14 +00:00
payload: HashMap<(Address, Address), TrafficEntry, Hash>,
2021-04-06 10:28:31 +00:00
pub dropped: TrafficEntry,
2019-01-09 16:45:12 +00:00
}
impl TrafficStats {
#[inline]
pub fn count_out_traffic(&mut self, peer: SocketAddr, bytes: usize) {
2021-01-28 22:19:20 +00:00
// HOT PATH
2019-02-14 22:39:16 +00:00
self.peers.entry(peer).or_insert_with(TrafficEntry::default).count_out(bytes);
2019-01-09 16:45:12 +00:00
}
#[inline]
pub fn count_in_traffic(&mut self, peer: SocketAddr, bytes: usize) {
2021-01-28 22:19:20 +00:00
// HOT PATH
2019-02-14 22:39:16 +00:00
self.peers.entry(peer).or_insert_with(TrafficEntry::default).count_in(bytes);
2019-01-09 16:45:12 +00:00
}
#[inline]
pub fn count_out_payload(&mut self, remote: Address, local: Address, bytes: usize) {
2021-01-28 22:19:20 +00:00
// HOT PATH
2019-02-14 22:39:16 +00:00
self.payload.entry((remote, local)).or_insert_with(TrafficEntry::default).count_out(bytes);
2019-01-09 16:45:12 +00:00
}
#[inline]
pub fn count_in_payload(&mut self, remote: Address, local: Address, bytes: usize) {
2021-01-28 22:19:20 +00:00
// HOT PATH
2019-02-14 22:39:16 +00:00
self.payload.entry((remote, local)).or_insert_with(TrafficEntry::default).count_in(bytes);
2019-01-09 16:45:12 +00:00
}
2020-05-29 08:04:14 +00:00
pub fn count_invalid_protocol(&mut self, bytes: usize) {
self.dropped.count_in(bytes)
}
pub fn count_dropped_payload(&mut self, bytes: usize) {
self.dropped.count_out(bytes)
}
2019-01-09 16:45:12 +00:00
pub fn period(&mut self, cleanup_idle: Option<usize>) {
for entry in self.peers.values_mut() {
entry.period();
}
for entry in self.payload.values_mut() {
entry.period();
}
2020-05-29 08:04:14 +00:00
self.dropped.period();
2019-01-09 16:45:12 +00:00
if let Some(periods) = cleanup_idle {
self.peers.retain(|_, entry| entry.idle_periods < periods);
self.payload.retain(|_, entry| entry.idle_periods < periods);
}
}
2019-12-04 08:32:35 +00:00
pub fn get_peer_traffic(&self) -> impl Iterator<Item = (&SocketAddr, &TrafficEntry)> {
2019-01-09 16:45:12 +00:00
self.peers.iter()
}
2019-12-04 08:32:35 +00:00
pub fn get_payload_traffic(&self) -> impl Iterator<Item = (&(Address, Address), &TrafficEntry)> {
2019-01-09 16:45:12 +00:00
self.payload.iter()
}
2020-05-29 09:51:04 +00:00
pub fn total_peer_traffic(&self) -> TrafficEntry {
let mut total = TrafficEntry::default();
for e in self.peers.values() {
total += e
}
total
}
pub fn total_payload_traffic(&self) -> TrafficEntry {
let mut total = TrafficEntry::default();
for e in self.payload.values() {
total += e
}
total
}
2019-01-09 16:45:12 +00:00
#[inline]
pub fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
2020-05-29 08:04:14 +00:00
writeln!(out, "peer_traffic:")?;
2019-01-09 16:45:12 +00:00
let mut peers: Vec<_> = self.get_peer_traffic().collect();
peers.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes));
for (addr, data) in peers.iter().rev() {
2020-05-29 08:04:14 +00:00
writeln!(
out,
" - peer: \"{}\"\n in: {{ display: \"{}/s\", bytes: {}, packets: {} }}\n out: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
addr_nice(**addr),
2020-05-30 14:12:54 +00:00
Bytes(data.in_bytes / STATS_INTERVAL as u64),
2020-05-29 08:04:14 +00:00
data.in_bytes,
data.in_packets,
2020-05-30 14:12:54 +00:00
Bytes(data.out_bytes / STATS_INTERVAL as u64),
2020-05-29 08:04:14 +00:00
data.out_bytes,
data.out_packets
)?;
2019-01-09 16:45:12 +00:00
}
2019-03-01 22:12:19 +00:00
writeln!(out)?;
2020-05-29 08:04:14 +00:00
writeln!(out, "payload_traffic:")?;
2019-01-09 16:45:12 +00:00
let mut payload: Vec<_> = self.get_payload_traffic().collect();
payload.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes));
for ((remote, local), data) in payload.iter().rev() {
2019-12-04 08:32:35 +00:00
writeln!(
out,
2020-05-29 08:04:14 +00:00
" - addrs: [\"{}\", \"{}\"]\n in: {{ display: \"{}/s\", bytes: {}, packets: {} }}\n out: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
2019-12-04 08:32:35 +00:00
remote,
local,
2020-05-30 14:12:54 +00:00
Bytes(data.in_bytes / STATS_INTERVAL as u64),
2020-05-29 08:04:14 +00:00
data.in_bytes,
data.in_packets,
2020-05-30 14:12:54 +00:00
Bytes(data.out_bytes / STATS_INTERVAL as u64),
2020-05-29 08:04:14 +00:00
data.out_bytes,
data.out_packets
2019-12-04 08:32:35 +00:00
)?;
2019-01-09 16:45:12 +00:00
}
2020-05-29 08:04:14 +00:00
writeln!(out)?;
writeln!(
out,
"invalid_protocol_traffic: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
2020-05-30 14:12:54 +00:00
Bytes(self.dropped.in_bytes / STATS_INTERVAL as u64),
2020-05-29 08:04:14 +00:00
self.dropped.in_bytes,
self.dropped.in_packets
)?;
writeln!(
out,
"dropped_payload_traffic: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
2020-05-30 14:12:54 +00:00
Bytes(self.dropped.out_bytes / STATS_INTERVAL as u64),
2020-05-29 08:04:14 +00:00
self.dropped.out_bytes,
self.dropped.out_packets
)?;
2019-01-09 16:45:12 +00:00
Ok(())
}
2019-02-14 22:39:16 +00:00
}