procinfo/net/
dev.rs

1//! Network device information from `/proc/net/dev`.
2
3use std::fs::File;
4use std::io::{Read, Result};
5
6use nom::{space, line_ending};
7use parsers::{
8    map_result,
9    parse_u64,
10};
11
12const NET_DEV_FILE: &'static str = "/proc/net/dev";
13
14/// Network device status information.
15///
16/// See `man 5 proc` and `Linux/net/core/net-procfs.c`
17pub struct DeviceStatus {
18    /// Name of the interface representing this device.
19    pub interface:           String,
20
21    /// Number of received bytes.
22    pub receive_bytes:       u64,
23    /// Number of received packets.
24    pub receive_packets:     u64,
25    /// Number of bad packets received.
26    pub receive_errs:        u64,
27    /// Number of incoming packets dropped.
28    pub receive_drop:        u64,
29    /// Number of incoming packets dropped due to fifo overrun.
30    pub receive_fifo:        u64,
31    /// Number of incoming packets dropped due to frame alignment errors.
32    pub receive_frame:       u64,
33    /// Number of CSLIP packets received.
34    pub receive_compressed:  u64,
35    /// Number of multicast packets received.
36    pub receive_multicast:   u64,
37
38    /// Number of transmitted bytes.
39    pub transmit_bytes:      u64,
40    /// Number of transmitted packets.
41    pub transmit_packets:    u64,
42    /// Number of occurred transmission problems.
43    pub transmit_errs:       u64,
44    /// Number of outgoing packets dropped.
45    pub transmit_drop:       u64,
46    /// Number of outgoing packets dropped due to fifo overrun.
47    pub transmit_fifo:       u64,
48    /// Number of occurred packet collisions.
49    pub transmit_colls:      u64,
50    /// Number of occurred carrier errors.
51    pub transmit_carrier:    u64,
52    /// Number of CSLIP packets transmitted.
53    pub transmit_compressed: u64,
54}
55
56named!(interface_stats<DeviceStatus>,
57    do_parse!(
58        opt!(space) >>
59        interface: take_until_and_consume!(":") >>
60        space >>
61        receive_bytes:       terminated!(parse_u64, space) >>
62        receive_packets:     terminated!(parse_u64, space) >>
63        receive_errs:        terminated!(parse_u64, space) >>
64        receive_drop:        terminated!(parse_u64, space) >>
65        receive_fifo:        terminated!(parse_u64, space) >>
66        receive_frame:       terminated!(parse_u64, space) >>
67        receive_compressed:  terminated!(parse_u64, space) >>
68        receive_multicast:   terminated!(parse_u64, space) >>
69        transmit_bytes:      terminated!(parse_u64, space) >>
70        transmit_packets:    terminated!(parse_u64, space) >>
71        transmit_errs:       terminated!(parse_u64, space) >>
72        transmit_drop:       terminated!(parse_u64, space) >>
73        transmit_fifo:       terminated!(parse_u64, space) >>
74        transmit_colls:      terminated!(parse_u64, space) >>
75        transmit_carrier:    terminated!(parse_u64, space) >>
76        transmit_compressed: parse_u64 >>
77        (DeviceStatus {
78            interface:           String::from_utf8_lossy(interface).to_string(),
79            receive_bytes:       receive_bytes,
80            receive_packets:     receive_packets,
81            receive_errs:        receive_errs,
82            receive_drop:        receive_drop,
83            receive_fifo:        receive_fifo,
84            receive_frame:       receive_frame,
85            receive_compressed:  receive_compressed,
86            receive_multicast:   receive_multicast,
87            transmit_bytes:      transmit_bytes,
88            transmit_packets:    transmit_packets,
89            transmit_errs:       transmit_errs,
90            transmit_drop:       transmit_drop,
91            transmit_fifo:       transmit_fifo,
92            transmit_colls:      transmit_colls,
93            transmit_carrier:    transmit_carrier,
94            transmit_compressed: transmit_compressed,
95        })));
96
97named!(interface_list< Vec<DeviceStatus> >,
98    do_parse!(
99        interfaces: separated_list!(line_ending, interface_stats) >>
100        line_ending >>
101        (interfaces)));
102
103named!(empty_list< Vec<DeviceStatus> >,
104    value!(Vec::new(), eof!()));
105
106named!(parse_dev< Vec<DeviceStatus> >,
107    do_parse!(
108        count!(take_until_and_consume!("\n"), 2) >>
109        interfaces: alt_complete!(interface_list | empty_list) >>
110        (interfaces)));
111
112/// Returns list of all network devices and information about their state.
113pub fn dev() -> Result<Vec<DeviceStatus>> {
114    let mut file = File::open(NET_DEV_FILE)?;
115
116    let mut buffer = vec![];
117    file.read_to_end(&mut buffer)?;
118
119    map_result(parse_dev(buffer.as_slice()))
120}
121
122#[cfg(test)]
123mod test {
124    use super::{dev, parse_dev};
125    use parsers::map_result;
126
127    #[test]
128    fn two_interfaces() {
129        let file = br#"Inter-|   Receive                                                |  Transmit
130 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
131    lo:  206950    2701    0    0    0     0          0         0   206950    2701    0    0    0     0       0          0
132wlp58s0: 631994599  596110    0    1    0     0          0         0 47170335  384943    0    0    0     0       0          0
133"#;
134        let interfaces = map_result(parse_dev(file)).unwrap();
135
136        assert!(interfaces.len() == 2);
137
138        assert!(interfaces[0].interface          == "lo");
139        assert!(interfaces[0].receive_bytes      == 206950);
140        assert!(interfaces[0].receive_packets    == 2701);
141        assert!(interfaces[0].receive_errs       == 0);
142        assert!(interfaces[0].receive_drop       == 0);
143        assert!(interfaces[0].receive_fifo       == 0);
144        assert!(interfaces[0].receive_frame      == 0);
145        assert!(interfaces[0].receive_compressed == 0);
146        assert!(interfaces[0].receive_multicast  == 0);
147        assert!(interfaces[0].transmit_bytes     == 206950);
148        assert!(interfaces[0].transmit_packets   == 2701);
149        assert!(interfaces[0].transmit_errs      == 0);
150        assert!(interfaces[0].transmit_drop      == 0);
151        assert!(interfaces[0].transmit_fifo      == 0);
152        assert!(interfaces[0].transmit_colls     == 0);
153        assert!(interfaces[0].transmit_carrier   == 0);
154
155        assert!(interfaces[1].interface           == "wlp58s0");
156        assert!(interfaces[1].receive_bytes       == 631994599);
157        assert!(interfaces[1].receive_packets     == 596110);
158        assert!(interfaces[1].receive_errs        == 0);
159        assert!(interfaces[1].receive_drop        == 1);
160        assert!(interfaces[1].receive_fifo        == 0);
161        assert!(interfaces[1].receive_frame       == 0);
162        assert!(interfaces[1].receive_multicast   == 0);
163        assert!(interfaces[1].transmit_bytes      == 47170335);
164        assert!(interfaces[1].transmit_packets    == 384943);
165        assert!(interfaces[1].transmit_errs       == 0);
166        assert!(interfaces[1].transmit_drop       == 0);
167        assert!(interfaces[1].transmit_fifo       == 0);
168        assert!(interfaces[1].transmit_colls      == 0);
169        assert!(interfaces[1].transmit_carrier    == 0);
170        assert!(interfaces[1].transmit_compressed == 0);
171    }
172
173    #[test]
174    fn no_interfaces() {
175        let file = br#"Inter-|   Receive                                                |  Transmit
176 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
177"#;
178        let interfaces = map_result(parse_dev(file)).unwrap();
179        assert!(interfaces.len() == 0);
180    }
181
182    #[test]
183    fn parse_native() {
184        dev().unwrap();
185    }
186}