Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_sys/src/net.rs

3.8 KiB, 1 run

created by r1870400018:10588, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! Per-interface network counters from `/proc/net/dev`.
2
3use crate::parse::{
4 parse_num,
5 read_to_string,
6 tokens,
7};
8
9use oxedyne_fe2o3_core::prelude::*;
10
11/// Cumulative byte and packet counters for one interface.
12#[derive(Clone, Debug, Default, PartialEq)]
13pub struct NetLine {
14 /// Interface name, e.g. `lo`, `eth0`, `wlp4s0`.
15 pub name: String,
16 /// Cumulative bytes received.
17 pub rx_bytes: u64,
18 /// Cumulative packets received.
19 pub rx_packets:u64,
20 /// Cumulative receive errors.
21 pub rx_errors: u64,
22 /// Cumulative receive packets dropped.
23 pub rx_drops: u64,
24 /// Cumulative bytes transmitted.
25 pub tx_bytes: u64,
26 /// Cumulative packets transmitted.
27 pub tx_packets:u64,
28 /// Cumulative transmit errors.
29 pub tx_errors: u64,
30 /// Cumulative transmit packets dropped.
31 pub tx_drops: u64,
32}
33
34/// Collection of per-interface counters.
35#[derive(Clone, Debug, Default, PartialEq)]
36pub struct NetStats {
37 pub interfaces: Vec<NetLine>,
38}
39
40impl NetStats {
41 /// Read `/proc/net/dev`.
42 pub fn sample() -> Outcome<Self> {
43 let content = res!(read_to_string("/proc/net/dev"));
44 Self::from_net_dev(&content)
45 }
46
47 /// Parse a `/proc/net/dev` body. The first two lines are
48 /// header rows describing the column groups; we skip them.
49 pub fn from_net_dev(content: &str) -> Outcome<Self> {
50 let mut out = Self::default();
51 for line in content.lines().skip(2) {
52 let (name_part, rest) = match line.split_once(':') {
53 Some(t) => t,
54 None => continue,
55 };
56 let toks = tokens(rest);
57 // 16 columns: rx (bytes packets errs drop fifo frame
58 // compressed multicast) then tx (same layout).
59 if toks.len() < 16 {
60 continue;
61 }
62 out.interfaces.push(NetLine {
63 name: name_part.trim().to_string(),
64 rx_bytes: res!(parse_num::<u64>(toks[0], "net.rx_bytes")),
65 rx_packets: res!(parse_num::<u64>(toks[1], "net.rx_packets")),
66 rx_errors: res!(parse_num::<u64>(toks[2], "net.rx_errors")),
67 rx_drops: res!(parse_num::<u64>(toks[3], "net.rx_drops")),
68 tx_bytes: res!(parse_num::<u64>(toks[8], "net.tx_bytes")),
69 tx_packets: res!(parse_num::<u64>(toks[9], "net.tx_packets")),
70 tx_errors: res!(parse_num::<u64>(toks[10], "net.tx_errors")),
71 tx_drops: res!(parse_num::<u64>(toks[11], "net.tx_drops")),
72 });
73 }
74 Ok(out)
75 }
76
77 /// Per-interface throughput between two samples.
78 pub fn deltas(&self, prev: &Self, elapsed_s: f64) -> Vec<NetDelta> {
79 let mut out = Vec::with_capacity(self.interfaces.len());
80 for iface in &self.interfaces {
81 let p = prev.interfaces.iter().find(|i| i.name == iface.name);
82 let p = match p {
83 Some(p) => p,
84 None => continue,
85 };
86 let rx = iface.rx_bytes.saturating_sub(p.rx_bytes);
87 let tx = iface.tx_bytes.saturating_sub(p.tx_bytes);
88 let (rxps, txps) = if elapsed_s > 0.0 {
89 (rx as f64 / elapsed_s, tx as f64 / elapsed_s)
90 } else {
91 (0.0, 0.0)
92 };
93 out.push(NetDelta {
94 name: iface.name.clone(),
95 rx_bps: rxps,
96 tx_bps: txps,
97 });
98 }
99 out
100 }
101}
102
103/// Per-interface throughput between two samples.
104#[derive(Clone, Debug, Default, PartialEq)]
105pub struct NetDelta {
106 pub name: String,
107 /// Bytes per second received over the interval.
108 pub rx_bps: f64,
109 /// Bytes per second transmitted over the interval.
110 pub tx_bps: f64,
111}