diff --git a/crates/tsunagi-cli/src/main.rs b/crates/tsunagi-cli/src/main.rs index 4f4c264..8060cb0 100644 --- a/crates/tsunagi-cli/src/main.rs +++ b/crates/tsunagi-cli/src/main.rs @@ -4078,6 +4078,8 @@ async fn build_report( handshake_secs_ago: tunnel.health.since_handshake.map(|s| s.as_secs()), tx_packets: tunnel.stats.tx_packets, rx_packets: tunnel.stats.rx_packets, + tx_bytes: tunnel.stats.tx_bytes, + rx_bytes: tunnel.stats.rx_bytes, dropped: tunnel.stats.dropped_wrong_source + tunnel.stats.dropped_oversize, protocol_errors: tunnel.stats.protocol_errors, @@ -4096,6 +4098,8 @@ async fn build_report( handshake_secs_ago: Some(tcp_tls.uptime_secs), tx_packets: tcp_tls.tx_packets, rx_packets: tcp_tls.rx_packets, + tx_bytes: tcp_tls.tx_bytes, + rx_bytes: tcp_tls.rx_bytes, dropped: tcp_tls.dropped, protocol_errors: 0, path: tcp_tls.path.clone(), @@ -4114,6 +4118,8 @@ async fn build_report( handshake_secs_ago: tunnel.health.since_handshake.map(|s| s.as_secs()), tx_packets: tunnel.stats.tx_packets, rx_packets: tunnel.stats.rx_packets, + tx_bytes: tunnel.stats.tx_bytes, + rx_bytes: tunnel.stats.rx_bytes, dropped: tunnel.stats.dropped_wrong_source + tunnel.stats.dropped_oversize, protocol_errors: tunnel.stats.protocol_errors, @@ -4131,6 +4137,8 @@ async fn build_report( handshake_secs_ago: None, tx_packets: 0, rx_packets: 0, + tx_bytes: 0, + rx_bytes: 0, dropped: 0, protocol_errors: 0, path: "no data link".into(), @@ -4147,6 +4155,8 @@ async fn build_report( handshake_secs_ago: None, tx_packets: 0, rx_packets: 0, + tx_bytes: 0, + rx_bytes: 0, dropped: 0, protocol_errors: 0, path: "no data link".into(), diff --git a/crates/tsunagi/src/dataplane/tunnel.rs b/crates/tsunagi/src/dataplane/tunnel.rs index 6da28ad..41a5597 100644 --- a/crates/tsunagi/src/dataplane/tunnel.rs +++ b/crates/tsunagi/src/dataplane/tunnel.rs @@ -83,6 +83,8 @@ struct TunnelPeerState { link: SharedLink, tx_packets: AtomicU64, rx_packets: AtomicU64, + tx_bytes: AtomicU64, + rx_bytes: AtomicU64, dropped: AtomicU64, established_at: std::time::Instant, } @@ -100,6 +102,10 @@ pub struct TunnelPeerReport { pub tx_packets: u64, /// Packets successfully received and decrypted. pub rx_packets: u64, + /// Plaintext bytes successfully encrypted and sent. + pub tx_bytes: u64, + /// Plaintext bytes successfully received and decrypted. + pub rx_bytes: u64, /// Packets dropped due to encryption/decryption/send failures. pub dropped: u64, /// Uptime in seconds since the data link was established. @@ -145,6 +151,8 @@ impl GenericTunnelPlugin { path: state.link.path_description(), tx_packets: state.tx_packets.load(Ordering::Relaxed), rx_packets: state.rx_packets.load(Ordering::Relaxed), + tx_bytes: state.tx_bytes.load(Ordering::Relaxed), + rx_bytes: state.rx_bytes.load(Ordering::Relaxed), dropped: state.dropped.load(Ordering::Relaxed), uptime_secs: state.established_at.elapsed().as_secs(), }) @@ -223,6 +231,9 @@ impl IpPlugin for GenericTunnelPlugin { Ok(ciphertext) => { if state.link.send(ciphertext).is_ok() { state.tx_packets.fetch_add(1, Ordering::Relaxed); + state + .tx_bytes + .fetch_add(packet.len() as u64, Ordering::Relaxed); true } else { state.dropped.fetch_add(1, Ordering::Relaxed); @@ -242,6 +253,8 @@ impl IpPlugin for GenericTunnelPlugin { link: Arc::clone(&link), tx_packets: AtomicU64::new(0), rx_packets: AtomicU64::new(0), + tx_bytes: AtomicU64::new(0), + rx_bytes: AtomicU64::new(0), dropped: AtomicU64::new(0), established_at: std::time::Instant::now(), }); @@ -268,6 +281,9 @@ impl IpPlugin for GenericTunnelPlugin { match codec.decrypt(network, peer, &payload) { Ok(packet) => { rx_state.rx_packets.fetch_add(1, Ordering::Relaxed); + rx_state + .rx_bytes + .fetch_add(packet.len() as u64, Ordering::Relaxed); if let Some(ref sink) = sink { sink.deliver(network, peer, packet).await; } diff --git a/crates/tsunagi/src/ipc/mod.rs b/crates/tsunagi/src/ipc/mod.rs index 70d6d9c..fcae9cd 100644 --- a/crates/tsunagi/src/ipc/mod.rs +++ b/crates/tsunagi/src/ipc/mod.rs @@ -472,6 +472,10 @@ pub struct OverlayPeerReport { pub tx_packets: u64, /// Packets decrypted from this peer. pub rx_packets: u64, + /// Plaintext bytes encrypted and sent to this peer. + pub tx_bytes: u64, + /// Plaintext bytes decrypted from this peer. + pub rx_bytes: u64, /// Data packets dropped: wrong source address, or too large for the path. pub dropped: u64, /// WireGuard protocol errors. @@ -605,7 +609,7 @@ pub const EXCHANGE_TIMEOUT: Duration = Duration::from_secs(5); /// /// Bump it whenever [`Request`], [`Response`] or anything they contain /// changes shape. -pub const CONTROL_PROTOCOL: u32 = u32::from_be_bytes([b'T', b'S', b'N', 15]); +pub const CONTROL_PROTOCOL: u32 = u32::from_be_bytes([b'T', b'S', b'N', 16]); /// Reads one request off an accepted stream, answers it, writes the response. ///