Source code
Revision control
Copy as Markdown
Other Tools
// Don't throw clippy warnings for manual string stripping.
// The suggested fix with `strip_prefix` removes support for Rust 1.33 and 1.38
#![allow(clippy::manual_strip)]
//! Information about the networking layer.
//!
//! This module corresponds to the `/proc/net` directory and contains various information about the
//! networking layer.
use crate::ProcResult;
use crate::{build_internal_error, expect, from_iter, from_str};
use std::collections::HashMap;
use bitflags::bitflags;
use std::io::BufRead;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::{path::PathBuf, str::FromStr};
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum TcpState {
Established = 1,
SynSent,
SynRecv,
FinWait1,
FinWait2,
TimeWait,
Close,
CloseWait,
LastAck,
Listen,
Closing,
NewSynRecv,
}
impl TcpState {
pub fn from_u8(num: u8) -> Option<TcpState> {
match num {
0x01 => Some(TcpState::Established),
0x02 => Some(TcpState::SynSent),
0x03 => Some(TcpState::SynRecv),
0x04 => Some(TcpState::FinWait1),
0x05 => Some(TcpState::FinWait2),
0x06 => Some(TcpState::TimeWait),
0x07 => Some(TcpState::Close),
0x08 => Some(TcpState::CloseWait),
0x09 => Some(TcpState::LastAck),
0x0A => Some(TcpState::Listen),
0x0B => Some(TcpState::Closing),
0x0C => Some(TcpState::NewSynRecv),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
TcpState::Established => 0x01,
TcpState::SynSent => 0x02,
TcpState::SynRecv => 0x03,
TcpState::FinWait1 => 0x04,
TcpState::FinWait2 => 0x05,
TcpState::TimeWait => 0x06,
TcpState::Close => 0x07,
TcpState::CloseWait => 0x08,
TcpState::LastAck => 0x09,
TcpState::Listen => 0x0A,
TcpState::Closing => 0x0B,
TcpState::NewSynRecv => 0x0C,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum UdpState {
Established = 1,
Close = 7,
}
impl UdpState {
pub fn from_u8(num: u8) -> Option<UdpState> {
match num {
0x01 => Some(UdpState::Established),
0x07 => Some(UdpState::Close),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
UdpState::Established => 0x01,
UdpState::Close => 0x07,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum UnixState {
UNCONNECTED = 1,
CONNECTING = 2,
CONNECTED = 3,
DISCONNECTING = 4,
}
impl UnixState {
pub fn from_u8(num: u8) -> Option<UnixState> {
match num {
0x01 => Some(UnixState::UNCONNECTED),
0x02 => Some(UnixState::CONNECTING),
0x03 => Some(UnixState::CONNECTED),
0x04 => Some(UnixState::DISCONNECTING),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
UnixState::UNCONNECTED => 0x01,
UnixState::CONNECTING => 0x02,
UnixState::CONNECTED => 0x03,
UnixState::DISCONNECTING => 0x04,
}
}
}
/// An entry in the TCP socket table
#[derive(Debug, Clone)]
#[non_exhaustive]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct TcpNetEntry {
pub local_address: SocketAddr,
pub remote_address: SocketAddr,
pub state: TcpState,
pub rx_queue: u32,
pub tx_queue: u32,
pub uid: u32,
pub inode: u64,
}
/// An entry in the UDP socket table
#[derive(Debug, Clone)]
#[non_exhaustive]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UdpNetEntry {
pub local_address: SocketAddr,
pub remote_address: SocketAddr,
pub state: UdpState,
pub rx_queue: u32,
pub tx_queue: u32,
pub uid: u32,
pub inode: u64,
}
/// An entry in the Unix socket table
#[derive(Debug, Clone)]
#[non_exhaustive]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UnixNetEntry {
/// The number of users of the socket
pub ref_count: u32,
/// The socket type.
///
/// Possible values are `SOCK_STREAM`, `SOCK_DGRAM`, or `SOCK_SEQPACKET`. These constants can
/// be found in the libc crate.
pub socket_type: u16,
/// The state of the socket
pub state: UnixState,
/// The inode number of the socket
pub inode: u64,
/// The bound pathname (if any) of the socket.
///
/// Sockets in the abstract namespace are included, and are shown with a path that commences
/// with the '@' character.
pub path: Option<PathBuf>,
}
/// Parses an address in the form 00010203:1234
///
/// Also supports IPv6
fn parse_addressport_str(s: &str, little_endian: bool) -> ProcResult<SocketAddr> {
let mut las = s.split(':');
let ip_part = expect!(las.next(), "ip_part");
let port = expect!(las.next(), "port");
let port = from_str!(u16, port, 16);
use std::convert::TryInto;
let read_u32 = if little_endian {
u32::from_le_bytes
} else {
u32::from_be_bytes
};
if ip_part.len() == 8 {
let bytes = expect!(hex::decode(ip_part));
let ip_u32 = read_u32(bytes[..4].try_into().unwrap());
let ip = Ipv4Addr::from(ip_u32);
Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
} else if ip_part.len() == 32 {
let bytes = expect!(hex::decode(ip_part));
let ip_a = read_u32(bytes[0..4].try_into().unwrap());
let ip_b = read_u32(bytes[4..8].try_into().unwrap());
let ip_c = read_u32(bytes[8..12].try_into().unwrap());
let ip_d = read_u32(bytes[12..16].try_into().unwrap());
let ip = Ipv6Addr::new(
((ip_a >> 16) & 0xffff) as u16,
(ip_a & 0xffff) as u16,
((ip_b >> 16) & 0xffff) as u16,
(ip_b & 0xffff) as u16,
((ip_c >> 16) & 0xffff) as u16,
(ip_c & 0xffff) as u16,
((ip_d >> 16) & 0xffff) as u16,
(ip_d & 0xffff) as u16,
);
Ok(SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)))
} else {
Err(build_internal_error!(format!(
"Unable to parse {:?} as an address:port",
s
)))
}
}
/// TCP socket entries.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct TcpNetEntries(pub Vec<TcpNetEntry>);
impl super::FromBufReadSI for TcpNetEntries {
fn from_buf_read<R: BufRead>(r: R, system_info: &crate::SystemInfo) -> ProcResult<Self> {
let mut vec = Vec::new();
// first line is a header we need to skip
for line in r.lines().skip(1) {
let line = line?;
let mut s = line.split_whitespace();
s.next();
let local_address = expect!(s.next(), "tcp::local_address");
let rem_address = expect!(s.next(), "tcp::rem_address");
let state = expect!(s.next(), "tcp::st");
let mut tx_rx_queue = expect!(s.next(), "tcp::tx_queue:rx_queue").splitn(2, ':');
let tx_queue = from_str!(u32, expect!(tx_rx_queue.next(), "tcp::tx_queue"), 16);
let rx_queue = from_str!(u32, expect!(tx_rx_queue.next(), "tcp::rx_queue"), 16);
s.next(); // skip tr and tm->when
s.next(); // skip retrnsmt
let uid = from_str!(u32, expect!(s.next(), "tcp::uid"));
s.next(); // skip timeout
let inode = expect!(s.next(), "tcp::inode");
vec.push(TcpNetEntry {
local_address: parse_addressport_str(local_address, system_info.is_little_endian())?,
remote_address: parse_addressport_str(rem_address, system_info.is_little_endian())?,
rx_queue,
tx_queue,
state: expect!(TcpState::from_u8(from_str!(u8, state, 16))),
uid,
inode: from_str!(u64, inode),
});
}
Ok(TcpNetEntries(vec))
}
}
/// UDP socket entries.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UdpNetEntries(pub Vec<UdpNetEntry>);
impl super::FromBufReadSI for UdpNetEntries {
fn from_buf_read<R: BufRead>(r: R, system_info: &crate::SystemInfo) -> ProcResult<Self> {
let mut vec = Vec::new();
// first line is a header we need to skip
for line in r.lines().skip(1) {
let line = line?;
let mut s = line.split_whitespace();
s.next();
let local_address = expect!(s.next(), "udp::local_address");
let rem_address = expect!(s.next(), "udp::rem_address");
let state = expect!(s.next(), "udp::st");
let mut tx_rx_queue = expect!(s.next(), "udp::tx_queue:rx_queue").splitn(2, ':');
let tx_queue: u32 = from_str!(u32, expect!(tx_rx_queue.next(), "udp::tx_queue"), 16);
let rx_queue: u32 = from_str!(u32, expect!(tx_rx_queue.next(), "udp::rx_queue"), 16);
s.next(); // skip tr and tm->when
s.next(); // skip retrnsmt
let uid = from_str!(u32, expect!(s.next(), "udp::uid"));
s.next(); // skip timeout
let inode = expect!(s.next(), "udp::inode");
vec.push(UdpNetEntry {
local_address: parse_addressport_str(local_address, system_info.is_little_endian())?,
remote_address: parse_addressport_str(rem_address, system_info.is_little_endian())?,
rx_queue,
tx_queue,
state: expect!(UdpState::from_u8(from_str!(u8, state, 16))),
uid,
inode: from_str!(u64, inode),
});
}
Ok(UdpNetEntries(vec))
}
}
/// Unix socket entries.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UnixNetEntries(pub Vec<UnixNetEntry>);
impl super::FromBufRead for UnixNetEntries {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut vec = Vec::new();
// first line is a header we need to skip
for line in r.lines().skip(1) {
let line = line?;
let mut s = line.split_whitespace();
s.next(); // skip table slot number
let ref_count = from_str!(u32, expect!(s.next()), 16);
s.next(); // skip protocol, always zero
s.next(); // skip internal kernel flags
let socket_type = from_str!(u16, expect!(s.next()), 16);
let state = from_str!(u8, expect!(s.next()), 16);
let inode = from_str!(u64, expect!(s.next()));
let path = s.next().map(PathBuf::from);
vec.push(UnixNetEntry {
ref_count,
socket_type,
inode,
state: expect!(UnixState::from_u8(state)),
path,
});
}
Ok(UnixNetEntries(vec))
}
}
/// An entry in the ARP table
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct ARPEntry {
/// IPv4 address
pub ip_address: Ipv4Addr,
/// Hardware type
///
/// This will almost always be ETHER (or maybe INFINIBAND)
pub hw_type: ARPHardware,
/// Internal kernel flags
pub flags: ARPFlags,
/// MAC Address
pub hw_address: Option<[u8; 6]>,
/// Device name
pub device: String,
}
bitflags! {
/// Hardware type for an ARP table entry.
// source: include/uapi/linux/if_arp.h
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct ARPHardware: u32 {
/// NET/ROM pseudo
const NETROM = 0;
/// Ethernet
const ETHER = 1;
/// Experimental ethernet
const EETHER = 2;
/// AX.25 Level 2
const AX25 = 3;
/// PROnet token ring
const PRONET = 4;
/// Chaosnet
const CHAOS = 5;
/// IEEE 802.2 Ethernet/TR/TB
const IEEE802 = 6;
/// Arcnet
const ARCNET = 7;
/// APPLEtalk
const APPLETLK = 8;
/// Frame Relay DLCI
const DLCI = 15;
/// ATM
const ATM = 19;
/// Metricom STRIP
const METRICOM = 23;
//// IEEE 1394 IPv4 - RFC 2734
const IEEE1394 = 24;
/// EUI-64
const EUI64 = 27;
/// InfiniBand
const INFINIBAND = 32;
}
}
bitflags! {
/// Flags for ARP entries
// source: include/uapi/linux/if_arp.h
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct ARPFlags: u32 {
/// Completed entry
const COM = 0x02;
/// Permanent entry
const PERM = 0x04;
/// Publish entry
const PUBL = 0x08;
/// Has requested trailers
const USETRAILERS = 0x10;
/// Want to use a netmask (only for proxy entries)
const NETMASK = 0x20;
// Don't answer this address
const DONTPUB = 0x40;
}
}
/// ARP table entries.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct ArpEntries(pub Vec<ARPEntry>);
impl super::FromBufRead for ArpEntries {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut vec = Vec::new();
// First line is a header we need to skip
for line in r.lines().skip(1) {
// Check if there might have been an IO error.
let line = line?;
let mut line = line.split_whitespace();
let ip_address = expect!(Ipv4Addr::from_str(expect!(line.next())));
let hw = from_str!(u32, &expect!(line.next())[2..], 16);
let hw = ARPHardware::from_bits_truncate(hw);
let flags = from_str!(u32, &expect!(line.next())[2..], 16);
let flags = ARPFlags::from_bits_truncate(flags);
let mac = expect!(line.next());
let mut mac: Vec<Result<u8, _>> = mac.split(':').map(|s| Ok(from_str!(u8, s, 16))).collect();
let mac = if mac.len() == 6 {
let mac_block_f = mac.pop().unwrap()?;
let mac_block_e = mac.pop().unwrap()?;
let mac_block_d = mac.pop().unwrap()?;
let mac_block_c = mac.pop().unwrap()?;
let mac_block_b = mac.pop().unwrap()?;
let mac_block_a = mac.pop().unwrap()?;
if mac_block_a == 0
&& mac_block_b == 0
&& mac_block_c == 0
&& mac_block_d == 0
&& mac_block_e == 0
&& mac_block_f == 0
{
None
} else {
Some([
mac_block_a,
mac_block_b,
mac_block_c,
mac_block_d,
mac_block_e,
mac_block_f,
])
}
} else {
None
};
// mask is always "*"
let _mask = expect!(line.next());
let dev = expect!(line.next());
vec.push(ARPEntry {
ip_address,
hw_type: hw,
flags,
hw_address: mac,
device: dev.to_string(),
})
}
Ok(ArpEntries(vec))
}
}
/// General statistics for a network interface/device
///
/// For an example, see the [interface_stats.rs](https://github.com/eminence/procfs/tree/master/examples)
/// example in the source repo.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct DeviceStatus {
/// Name of the interface
pub name: String,
/// Total bytes received
pub recv_bytes: u64,
/// Total packets received
pub recv_packets: u64,
/// Bad packets received
pub recv_errs: u64,
/// Packets dropped
pub recv_drop: u64,
/// Fifo overrun
pub recv_fifo: u64,
/// Frame alignment errors
pub recv_frame: u64,
/// Number of compressed packets received
pub recv_compressed: u64,
/// Number of multicast packets received
pub recv_multicast: u64,
/// Total bytes transmitted
pub sent_bytes: u64,
/// Total packets transmitted
pub sent_packets: u64,
/// Number of transmission errors
pub sent_errs: u64,
/// Number of packets dropped during transmission
pub sent_drop: u64,
pub sent_fifo: u64,
/// Number of collisions
pub sent_colls: u64,
/// Number of packets not sent due to carrier errors
pub sent_carrier: u64,
/// Number of compressed packets transmitted
pub sent_compressed: u64,
}
impl DeviceStatus {
fn from_str(s: &str) -> ProcResult<DeviceStatus> {
let mut split = s.split_whitespace();
let name: String = expect!(from_iter(&mut split));
let recv_bytes = expect!(from_iter(&mut split));
let recv_packets = expect!(from_iter(&mut split));
let recv_errs = expect!(from_iter(&mut split));
let recv_drop = expect!(from_iter(&mut split));
let recv_fifo = expect!(from_iter(&mut split));
let recv_frame = expect!(from_iter(&mut split));
let recv_compressed = expect!(from_iter(&mut split));
let recv_multicast = expect!(from_iter(&mut split));
let sent_bytes = expect!(from_iter(&mut split));
let sent_packets = expect!(from_iter(&mut split));
let sent_errs = expect!(from_iter(&mut split));
let sent_drop = expect!(from_iter(&mut split));
let sent_fifo = expect!(from_iter(&mut split));
let sent_colls = expect!(from_iter(&mut split));
let sent_carrier = expect!(from_iter(&mut split));
let sent_compressed = expect!(from_iter(&mut split));
Ok(DeviceStatus {
name: name.trim_end_matches(':').to_owned(),
recv_bytes,
recv_packets,
recv_errs,
recv_drop,
recv_fifo,
recv_frame,
recv_compressed,
recv_multicast,
sent_bytes,
sent_packets,
sent_errs,
sent_drop,
sent_fifo,
sent_colls,
sent_carrier,
sent_compressed,
})
}
}
/// Device status information for all network interfaces.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct InterfaceDeviceStatus(pub HashMap<String, DeviceStatus>);
impl super::FromBufRead for InterfaceDeviceStatus {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut map = HashMap::new();
// the first two lines are headers, so skip them
for line in r.lines().skip(2) {
let dev = DeviceStatus::from_str(&line?)?;
map.insert(dev.name.clone(), dev);
}
Ok(InterfaceDeviceStatus(map))
}
}
/// An entry in the ipv4 route table
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct RouteEntry {
/// Interface to which packets for this route will be sent
pub iface: String,
/// The destination network or destination host
pub destination: Ipv4Addr,
pub gateway: Ipv4Addr,
pub flags: u16,
/// Number of references to this route
pub refcnt: u16,
/// Count of lookups for the route
pub in_use: u16,
/// The 'distance' to the target (usually counted in hops)
pub metrics: u32,
pub mask: Ipv4Addr,
/// Default maximum transmission unit for TCP connections over this route
pub mtu: u32,
/// Default window size for TCP connections over this route
pub window: u32,
/// Initial RTT (Round Trip Time)
pub irtt: u32,
}
/// A set of ipv4 routes.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct RouteEntries(pub Vec<RouteEntry>);
impl super::FromBufRead for RouteEntries {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut vec = Vec::new();
// First line is a header we need to skip
for line in r.lines().skip(1) {
// Check if there might have been an IO error.
let line = line?;
let mut line = line.split_whitespace();
// network interface name, e.g. eth0
let iface = expect!(line.next());
let destination = from_str!(u32, expect!(line.next()), 16).to_ne_bytes().into();
let gateway = from_str!(u32, expect!(line.next()), 16).to_ne_bytes().into();
let flags = from_str!(u16, expect!(line.next()), 16);
let refcnt = from_str!(u16, expect!(line.next()), 10);
let in_use = from_str!(u16, expect!(line.next()), 10);
let metrics = from_str!(u32, expect!(line.next()), 10);
let mask = from_str!(u32, expect!(line.next()), 16).to_ne_bytes().into();
let mtu = from_str!(u32, expect!(line.next()), 10);
let window = from_str!(u32, expect!(line.next()), 10);
let irtt = from_str!(u32, expect!(line.next()), 10);
vec.push(RouteEntry {
iface: iface.to_string(),
destination,
gateway,
flags,
refcnt,
in_use,
metrics,
mask,
mtu,
window,
irtt,
});
}
Ok(RouteEntries(vec))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
/// The indication of whether this entity is acting as an IP gateway in respect
/// to the forwarding of datagrams received by, but not addressed to, this
/// entity. IP gateways forward datagrams. IP hosts do not (except those
/// source-routed via the host).
///
/// Note that for some managed nodes, this object may take on only a subset of
/// the values possible. Accordingly, it is appropriate for an agent to return a
/// `badValue` response if a management station attempts to change this object
/// to an inappropriate value.
pub enum IpForwarding {
/// Acting as a gateway
Forwarding = 1,
/// Not acting as a gateway
NotForwarding = 2,
}
impl IpForwarding {
pub fn from_u8(num: u8) -> Option<IpForwarding> {
match num {
1 => Some(IpForwarding::Forwarding),
2 => Some(IpForwarding::NotForwarding),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
IpForwarding::Forwarding => 1,
IpForwarding::NotForwarding => 2,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
/// The algorithm used to determine the timeout value used for retransmitting
/// unacknowledged octets.
pub enum TcpRtoAlgorithm {
/// None of the following
Other = 1,
/// A constant rto
Constant = 2,
Rsre = 3,
/// Van Jacobson's algorithm
///
/// Reference: Jacobson, V., "Congestion Avoidance and Control", SIGCOMM 1988, Stanford, California.
Vanj = 4,
}
impl TcpRtoAlgorithm {
pub fn from_u8(num: u8) -> Option<TcpRtoAlgorithm> {
match num {
1 => Some(TcpRtoAlgorithm::Other),
2 => Some(TcpRtoAlgorithm::Constant),
3 => Some(TcpRtoAlgorithm::Rsre),
4 => Some(TcpRtoAlgorithm::Vanj),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
TcpRtoAlgorithm::Other => 1,
TcpRtoAlgorithm::Constant => 2,
TcpRtoAlgorithm::Rsre => 3,
TcpRtoAlgorithm::Vanj => 4,
}
}
}
/// This struct holds the data needed for the IP, ICMP, TCP, and UDP management
/// information bases for an SNMP agent.
///
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Snmp {
pub ip_forwarding: IpForwarding,
/// The default value inserted into the Time-To-Live field of the IP header
/// of datagrams originated at this entity, whenever a TTL value is not
/// supplied by the transport layer protocol.
pub ip_default_ttl: u32,
/// The total number of input datagrams received from interfaces, including
/// those received in error.
pub ip_in_receives: u64,
/// The number of input datagrams discarded due to errors in their IP
/// headers.
pub ip_in_hdr_errors: u64,
/// The number of input datagrams discarded because the IP address in their
/// IP header's destination field was not a valid address to be received at
/// this entity.
pub ip_in_addr_errors: u64,
/// The number of input datagrams for which this entity was not their final
/// IP destination, as a result of which an attempt was made to find a
/// route to forward them to that final destination.
pub ip_forw_datagrams: u64,
/// The number of locally-addressed datagrams received successfully but
/// discarded because of an unknown or unsupported protocol.
pub ip_in_unknown_protos: u64,
/// The number of input IP datagrams for which no problems were encountered
/// to prevent their continued processing, but which were discarded
/// (e.g., for lack of buffer space).
pub ip_in_discards: u64,
/// The total number of input datagrams successfully delivered to IP
/// user-protocols (including ICMP).
///
/// Note that this counter does not include any datagrams discarded while
/// awaiting re-assembly.
pub ip_in_delivers: u64,
/// The total number of IP datagrams which local IP user-protocols
/// (including ICMP) supplied to IP in requests for transmission.
///
/// Note that this counter does not include any datagrams counted in
/// ipForwDatagrams.
pub ip_out_requests: u64,
/// The number of output IP datagrams for which no problem was encountered
/// to prevent their transmission to their destination, but which were
/// discarded (e.g., for lack of buffer space).
///
/// Note that this counter would include datagrams counted in
/// `IpForwDatagrams` if any such packets met this (discretionary) discard
/// criterion.
pub ip_out_discards: u64,
/// The number of IP datagrams discarded because no route could be found to
/// transmit them to their destination.
///
/// Note that this counter includes any packets counted in `IpForwDatagrams`
/// which meet this `no-route' criterion.
///
/// Note that this includes any datagarms which a host cannot route because
/// all of its default gateways are down.
pub ip_out_no_routes: u64,
/// The maximum number of seconds which received fragments are held while
/// they are awaiting reassembly at this entity.
pub ip_reasm_timeout: u64,
/// The number of IP fragments received which needed to be reassembled at
/// this entity.
pub ip_reasm_reqds: u64,
/// The number of IP datagrams successfully re-assembled.
pub ip_reasm_oks: u64,
/// The number of failures detected by the IP re-assembly algorithm
/// (for whatever reason: timed out, errors, etc).
///
/// Note that this is not necessarily a count of discarded IP fragments
/// since some algorithms (notably the algorithm in [RFC 815](https://datatracker.ietf.org/doc/html/rfc815))
/// can lose track of the number of fragments by combining them as they are
/// received.
pub ip_reasm_fails: u64,
/// The number of IP datagrams that have been successfully fragmented at
/// this entity.
pub ip_frag_oks: u64,
/// The number of IP datagrams that have been discarded because they needed
/// to be fragmented at this entity but could not be, e.g., because their
/// `Don't Fragment` flag was set.
pub ip_frag_fails: u64,
/// The number of IP datagram fragments that have been generated as a result
/// of fragmentation at this entity.
pub ip_frag_creates: u64,
/// The total number of ICMP messages which the entity received.
///
/// Note that this counter includes all those counted by `icmp_in_errors`.
pub icmp_in_msgs: u64,
/// The number of ICMP messages which the entity received but determined as
/// having ICMP-specific errors (bad ICMP checksums, bad length, etc.
pub icmp_in_errors: u64,
/// This counter indicates the checksum of the ICMP packet is wrong.
///
/// Non RFC1213 field
pub icmp_in_csum_errors: u64,
/// The number of ICMP Destination Unreachable messages received.
pub icmp_in_dest_unreachs: u64,
/// The number of ICMP Time Exceeded messages received.
pub icmp_in_time_excds: u64,
/// The number of ICMP Parameter Problem messages received.
pub icmp_in_parm_probs: u64,
/// The number of ICMP Source Quench messages received.
pub icmp_in_src_quenchs: u64,
/// The number of ICMP Redirect messages received.
pub icmp_in_redirects: u64,
/// The number of ICMP Echo (request) messages received.
pub icmp_in_echos: u64,
/// The number of ICMP Echo Reply messages received.
pub icmp_in_echo_reps: u64,
/// The number of ICMP Timestamp (request) messages received.
pub icmp_in_timestamps: u64,
/// The number of ICMP Timestamp Reply messages received.
pub icmp_in_timestamp_reps: u64,
/// The number of ICMP Address Mask Request messages received.
pub icmp_in_addr_masks: u64,
/// The number of ICMP Address Mask Reply messages received.
pub icmp_in_addr_mask_reps: u64,
/// The total number of ICMP messages which this entity attempted to send.
///
/// Note that this counter includes all those counted by `icmp_out_errors`.
pub icmp_out_msgs: u64,
/// The number of ICMP messages which this entity did not send due to
/// problems discovered within ICMP such as a lack of buffers. This value
/// should not include errors discovered outside the ICMP layer such as the
/// inability of IP to route the resultant datagram. In some
/// implementations there may be no types of error which contribute to this
/// counter's value.
pub icmp_out_errors: u64,
/// The number of ICMP Destination Unreachable messages sent.
pub icmp_out_dest_unreachs: u64,
/// The number of ICMP Time Exceeded messages sent.
pub icmp_out_time_excds: u64,
/// The number of ICMP Parameter Problem messages sent.
pub icmp_out_parm_probs: u64,
/// The number of ICMP Source Quench messages sent.
pub icmp_out_src_quenchs: u64,
/// The number of ICMP Redirect messages sent. For a host, this object will
/// always be zero, since hosts do not send redirects.
pub icmp_out_redirects: u64,
/// The number of ICMP Echo (request) messages sent.
pub icmp_out_echos: u64,
/// The number of ICMP Echo Reply messages sent.
pub icmp_out_echo_reps: u64,
/// The number of ICMP Timestamp (request) messages sent.
pub icmp_out_timestamps: u64,
/// The number of ICMP Timestamp Reply messages sent.
pub icmp_out_timestamp_reps: u64,
/// The number of ICMP Address Mask Request messages sent.
pub icmp_out_addr_masks: u64,
/// The number of ICMP Address Mask Reply messages sent.
pub icmp_out_addr_mask_reps: u64,
// ignore ICMP numeric types
pub tcp_rto_algorithm: TcpRtoAlgorithm,
/// The minimum value permitted by a TCP implementation for the
/// retransmission timeout, measured in milliseconds. More refined
/// semantics for objects of this type depend upon the algorithm used to
/// determine the retransmission timeout. In particular, when the timeout
/// algorithm is rsre(3), an object of this type has the semantics of the
pub tcp_rto_min: u64,
/// The maximum value permitted by a TCP implementation for the
/// retransmission timeout, measured in milliseconds. More refined
/// semantics for objects of this type depend upon the algorithm used to
/// determine the retransmission timeout. In particular, when the timeout
/// algorithm is rsre(3), an object of this type has the semantics of the
pub tcp_rto_max: u64,
/// The limit on the total number of TCP connections the entity can support.
/// In entities where the maximum number of connections is dynamic, this
/// object should contain the value -1.
pub tcp_max_conn: i64,
/// The number of times TCP connections have made a direct transition to the
/// SYN-SENT state from the CLOSED state.
pub tcp_active_opens: u64,
/// The number of times TCP connections have made a direct transition to the
/// SYN-RCVD state from the LISTEN state.
pub tcp_passive_opens: u64,
/// The number of times TCP connections have made a direct transition to the
/// CLOSED state from either the SYN-SENT state or the SYN-RCVD state, plus
/// the number of times TCP connections have made a direct transition to the
/// LISTEN state from the SYN-RCVD state.
pub tcp_attempt_fails: u64,
/// The number of times TCP connections have made a direct transition to the
/// CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state.
pub tcp_estab_resets: u64,
/// The number of TCP connections for which the current state is either
/// ESTABLISHED or CLOSE-WAIT.
pub tcp_curr_estab: u64,
/// The total number of segments received, including those received in
/// error. This count includes segments received on currently established
/// connections.
pub tcp_in_segs: u64,
/// The total number of segments sent, including those on current
/// connections but excluding those containing only retransmitted octets.
pub tcp_out_segs: u64,
/// The total number of segments retransmitted - that is, the number of TCP
/// segments transmitted containing one or more previously transmitted octets.
pub tcp_retrans_segs: u64,
/// The total number of segments received in error (e.g., bad TCP checksums).
pub tcp_in_errs: u64,
/// The number of TCP segments sent containing the RST flag.
pub tcp_out_rsts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub tcp_in_csum_errors: u64,
/// The total number of UDP datagrams delivered to UDP users.
pub udp_in_datagrams: u64,
/// The total number of received UDP datagrams for which there was no
/// application at the destination port.
pub udp_no_ports: u64,
/// The number of received UDP datagrams that could not be delivered for
/// reasons other than the lack of an application at the destination port.
pub udp_in_errors: u64,
/// The total number of UDP datagrams sent from this entity.
pub udp_out_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_rcvbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_sndbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_in_csum_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_ignored_multi: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_no_ports: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_out_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_rcvbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_sndbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_csum_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_ignored_multi: u64,
}
impl super::FromBufRead for Snmp {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
fn next_group<R: BufRead>(lines: &mut std::io::Lines<R>, prefix: &str) -> ProcResult<String> {
if cfg!(test) {
let line = lines.next().unwrap()?;
if !line.starts_with(prefix) {
return Err(build_internal_error!(format!(
"`{}` section not found in /proc/net/snmp",
prefix
)));
}
let line = lines.next().unwrap()?;
if !line.starts_with(prefix) {
return Err(build_internal_error!(format!(
"`{}` section not found in /proc/net/snmp",
prefix
)));
}
return Ok(line);
} else {
Ok(lines.skip(1).next().unwrap()?)
}
}
fn expect_none(line: Option<&str>, msg: &str) -> ProcResult<()> {
if cfg!(test) {
match line {
Some(..) => Err(build_internal_error!(format!("`{}` section is not consumed", msg))),
None => Ok(()),
}
} else {
Ok(())
}
}
let mut lines = r.lines();
let ip = next_group(&mut lines, "Ip:")?;
let mut ip = ip.split_whitespace().skip(1);
let icmp = next_group(&mut lines, "Icmp:")?;
let mut icmp = icmp.split_whitespace().skip(1);
let _ = next_group(&mut lines, "IcmpMsg:")?;
let tcp = next_group(&mut lines, "Tcp:")?;
let mut tcp = tcp.split_whitespace().skip(1);
let udp = next_group(&mut lines, "Udp:")?;
let mut udp = udp.split_whitespace().skip(1);
let udp_lite = next_group(&mut lines, "UdpLite:")?;
let mut udp_lite = udp_lite.split_whitespace().skip(1);
let snmp = Snmp {
// Ip
ip_forwarding: expect!(IpForwarding::from_u8(from_str!(u8, expect!(ip.next())))),
ip_default_ttl: from_str!(u32, expect!(ip.next())),
ip_in_receives: from_str!(u64, expect!(ip.next())),
ip_in_hdr_errors: from_str!(u64, expect!(ip.next())),
ip_in_addr_errors: from_str!(u64, expect!(ip.next())),
ip_forw_datagrams: from_str!(u64, expect!(ip.next())),
ip_in_unknown_protos: from_str!(u64, expect!(ip.next())),
ip_in_discards: from_str!(u64, expect!(ip.next())),
ip_in_delivers: from_str!(u64, expect!(ip.next())),
ip_out_requests: from_str!(u64, expect!(ip.next())),
ip_out_discards: from_str!(u64, expect!(ip.next())),
ip_out_no_routes: from_str!(u64, expect!(ip.next())),
ip_reasm_timeout: from_str!(u64, expect!(ip.next())),
ip_reasm_reqds: from_str!(u64, expect!(ip.next())),
ip_reasm_oks: from_str!(u64, expect!(ip.next())),
ip_reasm_fails: from_str!(u64, expect!(ip.next())),
ip_frag_oks: from_str!(u64, expect!(ip.next())),
ip_frag_fails: from_str!(u64, expect!(ip.next())),
ip_frag_creates: from_str!(u64, expect!(ip.next())),
// Icmp
icmp_in_msgs: from_str!(u64, expect!(icmp.next())),
icmp_in_errors: from_str!(u64, expect!(icmp.next())),
icmp_in_csum_errors: from_str!(u64, expect!(icmp.next())),
icmp_in_dest_unreachs: from_str!(u64, expect!(icmp.next())),
icmp_in_time_excds: from_str!(u64, expect!(icmp.next())),
icmp_in_parm_probs: from_str!(u64, expect!(icmp.next())),
icmp_in_src_quenchs: from_str!(u64, expect!(icmp.next())),
icmp_in_redirects: from_str!(u64, expect!(icmp.next())),
icmp_in_echos: from_str!(u64, expect!(icmp.next())),
icmp_in_echo_reps: from_str!(u64, expect!(icmp.next())),
icmp_in_timestamps: from_str!(u64, expect!(icmp.next())),
icmp_in_timestamp_reps: from_str!(u64, expect!(icmp.next())),
icmp_in_addr_masks: from_str!(u64, expect!(icmp.next())),
icmp_in_addr_mask_reps: from_str!(u64, expect!(icmp.next())),
icmp_out_msgs: from_str!(u64, expect!(icmp.next())),
icmp_out_errors: from_str!(u64, expect!(icmp.next())),
icmp_out_dest_unreachs: from_str!(u64, expect!(icmp.next())),
icmp_out_time_excds: from_str!(u64, expect!(icmp.next())),
icmp_out_parm_probs: from_str!(u64, expect!(icmp.next())),
icmp_out_src_quenchs: from_str!(u64, expect!(icmp.next())),
icmp_out_redirects: from_str!(u64, expect!(icmp.next())),
icmp_out_echos: from_str!(u64, expect!(icmp.next())),
icmp_out_echo_reps: from_str!(u64, expect!(icmp.next())),
icmp_out_timestamps: from_str!(u64, expect!(icmp.next())),
icmp_out_timestamp_reps: from_str!(u64, expect!(icmp.next())),
icmp_out_addr_masks: from_str!(u64, expect!(icmp.next())),
icmp_out_addr_mask_reps: from_str!(u64, expect!(icmp.next())),
// Tcp
tcp_rto_algorithm: expect!(TcpRtoAlgorithm::from_u8(from_str!(u8, expect!(tcp.next())))),
tcp_rto_min: from_str!(u64, expect!(tcp.next())),
tcp_rto_max: from_str!(u64, expect!(tcp.next())),
tcp_max_conn: from_str!(i64, expect!(tcp.next())),
tcp_active_opens: from_str!(u64, expect!(tcp.next())),
tcp_passive_opens: from_str!(u64, expect!(tcp.next())),
tcp_attempt_fails: from_str!(u64, expect!(tcp.next())),
tcp_estab_resets: from_str!(u64, expect!(tcp.next())),
tcp_curr_estab: from_str!(u64, expect!(tcp.next())),
tcp_in_segs: from_str!(u64, expect!(tcp.next())),
tcp_out_segs: from_str!(u64, expect!(tcp.next())),
tcp_retrans_segs: from_str!(u64, expect!(tcp.next())),
tcp_in_errs: from_str!(u64, expect!(tcp.next())),
tcp_out_rsts: from_str!(u64, expect!(tcp.next())),
tcp_in_csum_errors: from_str!(u64, expect!(tcp.next())),
// Udp
udp_in_datagrams: from_str!(u64, expect!(udp.next())),
udp_no_ports: from_str!(u64, expect!(udp.next())),
udp_in_errors: from_str!(u64, expect!(udp.next())),
udp_out_datagrams: from_str!(u64, expect!(udp.next())),
udp_rcvbuf_errors: from_str!(u64, expect!(udp.next())),
udp_sndbuf_errors: from_str!(u64, expect!(udp.next())),
udp_in_csum_errors: from_str!(u64, expect!(udp.next())),
udp_ignored_multi: from_str!(u64, expect!(udp.next())),
// UdpLite
udp_lite_in_datagrams: from_str!(u64, expect!(udp_lite.next())),
udp_lite_no_ports: from_str!(u64, expect!(udp_lite.next())),
udp_lite_in_errors: from_str!(u64, expect!(udp_lite.next())),
udp_lite_out_datagrams: from_str!(u64, expect!(udp_lite.next())),
udp_lite_rcvbuf_errors: from_str!(u64, expect!(udp_lite.next())),
udp_lite_sndbuf_errors: from_str!(u64, expect!(udp_lite.next())),
udp_lite_in_csum_errors: from_str!(u64, expect!(udp_lite.next())),
udp_lite_ignored_multi: from_str!(u64, expect!(udp_lite.next())),
};
expect_none(ip.next(), "Ip")?;
expect_none(icmp.next(), "Icmp")?;
expect_none(tcp.next(), "Tcp")?;
expect_none(udp.next(), "Udp")?;
expect_none(udp_lite.next(), "UdpLite")?;
Ok(snmp)
}
}
/// This struct holds the data needed for the IP, ICMP, TCP, and UDP management
/// information bases for an SNMP agent.
///
/// Note that this struct is only for IPv6
///
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Snmp6 {
/// The total number of input datagrams received from interfaces, including
/// those received in error.
pub ip_in_receives: u64,
/// The number of input datagrams discarded due to errors in their IP
/// headers.
pub ip_in_hdr_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_too_big_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_no_routes: u64,
/// The number of input datagrams discarded because the IP address in their
/// IP header's destination field was not a valid address to be received at
/// this entity.
pub ip_in_addr_errors: u64,
/// The number of locally-addressed datagrams received successfully but
/// discarded because of an unknown or unsupported protocol.
pub ip_in_unknown_protos: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_truncated_pkts: u64,
/// The number of input IP datagrams for which no problems were encountered
/// to prevent their continued processing, but which were discarded
/// (e.g., for lack of buffer space).
pub ip_in_discards: u64,
/// The total number of input datagrams successfully delivered to IP
/// user-protocols (including ICMP).
///
/// Note that this counter does not include any datagrams discarded while
/// awaiting re-assembly.
pub ip_in_delivers: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_forw_datagrams: u64,
/// The total number of IP datagrams which local IP user-protocols
/// (including ICMP) supplied to IP in requests for transmission.
///
/// Note that this counter does not include any datagrams counted in
/// ipForwDatagrams.
pub ip_out_requests: u64,
/// The number of output IP datagrams for which no problem was encountered
/// to prevent their transmission to their destination, but which were
/// discarded (e.g., for lack of buffer space).
///
/// Note that this counter would include datagrams counted in
/// `IpForwDatagrams` if any such packets met this (discretionary) discard
/// criterion.
pub ip_out_discards: u64,
/// The number of IP datagrams discarded because no route could be found to
/// transmit them to their destination.
///
/// Note that this counter includes any packets counted in `IpForwDatagrams`
/// which meet this `no-route' criterion.
///
/// Note that this includes any datagarms which a host cannot route because
/// all of its default gateways are down.
pub ip_out_no_routes: u64,
/// The maximum number of seconds which received fragments are held while
/// they are awaiting reassembly at this entity.
pub ip_reasm_timeout: u64,
/// The number of IP fragments received which needed to be reassembled at
/// this entity.
pub ip_reasm_reqds: u64,
/// The number of IP datagrams successfully re-assembled.
pub ip_reasm_oks: u64,
/// The number of failures detected by the IP re-assembly algorithm
/// (for whatever reason: timed out, errors, etc).
///
/// Note that this is not necessarily a count of discarded IP fragments
/// since some algorithms (notably the algorithm in [RFC 815](https://datatracker.ietf.org/doc/html/rfc815))
/// can lose track of the number of fragments by combining them as they are
/// received.
pub ip_reasm_fails: u64,
/// The number of IP datagrams that have been successfully fragmented at
/// this entity.
pub ip_frag_oks: u64,
/// The number of IP datagrams that have been discarded because they needed
/// to be fragmented at this entity but could not be, e.g., because their
/// `Don't Fragment` flag was set.
pub ip_frag_fails: u64,
/// The number of IP datagram fragments that have been generated as a result
/// of fragmentation at this entity.
pub ip_frag_creates: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_mcast_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_mcast_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_mcast_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_mcast_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_bcast_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_out_bcast_octets: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_no_ect_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_ect1_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_ect0_pkts: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub ip_in_ce_pkts: u64,
/// The total number of ICMP messages which the entity received.
///
/// Note that this counter includes all those counted by `icmp_in_errors`.
pub icmp_in_msgs: u64,
/// The number of ICMP messages which the entity received but determined as
/// having ICMP-specific errors (bad ICMP checksums, bad length, etc.
pub icmp_in_errors: u64,
/// The total number of ICMP messages which this entity attempted to send.
///
/// Note that this counter includes all those counted by `icmp_out_errors`.
pub icmp_out_msgs: u64,
/// The number of ICMP messages which this entity did not send due to
/// problems discovered within ICMP such as a lack of buffers. This value
/// should not include errors discovered outside the ICMP layer such as the
/// inability of IP to route the resultant datagram. In some
/// implementations there may be no types of error which contribute to this
/// counter's value.
pub icmp_out_errors: u64,
/// This counter indicates the checksum of the ICMP packet is wrong.
///
/// Non RFC1213 field
pub icmp_in_csum_errors: u64,
/// The number of ICMP Destination Unreachable messages received.
pub icmp_in_dest_unreachs: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_pkt_too_bigs: u64,
/// The number of ICMP Time Exceeded messages received.
pub icmp_in_time_excds: u64,
/// The number of ICMP Parameter Problem messages received.
pub icmp_in_parm_problem: u64,
/// The number of ICMP Echo (request) messages received.
pub icmp_in_echos: u64,
/// The number of ICMP Echo Reply messages received.
pub icmp_in_echo_replies: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_group_memb_queries: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_group_memb_responses: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_group_memb_reductions: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_router_solicits: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_router_advertisements: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_neighbor_solicits: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_neighbor_advertisements: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_redirects: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_in_mldv2_reports: u64,
/// The number of ICMP Destination Unreachable messages sent.
pub icmp_out_dest_unreachs: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_pkt_too_bigs: u64,
/// The number of ICMP Time Exceeded messages sent.
pub icmp_out_time_excds: u64,
/// The number of ICMP Parameter Problem messages sent.
pub icmp_out_parm_problems: u64,
/// The number of ICMP Echo (request) messages sent.
pub icmp_out_echos: u64,
/// The number of ICMP Echo Reply messages sent.
pub icmp_out_echo_replies: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_group_memb_queries: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_group_memb_responses: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_group_memb_reductions: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_router_solicits: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_router_advertisements: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_neighbor_solicits: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_neighbor_advertisements: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_redirects: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub icmp_out_mldv2_reports: u64,
//
// ignore ICMP numeric types
//
/// The total number of UDP datagrams delivered to UDP users.
pub udp_in_datagrams: u64,
/// The total number of received UDP datagrams for which there was no
/// application at the destination port.
pub udp_no_ports: u64,
/// The number of received UDP datagrams that could not be delivered for
/// reasons other than the lack of an application at the destination port.
pub udp_in_errors: u64,
/// The total number of UDP datagrams sent from this entity.
pub udp_out_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_rcvbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_sndbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_in_csum_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_ignored_multi: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_no_ports: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_out_datagrams: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_rcvbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_sndbuf_errors: u64,
/// [To be documented.]
///
/// Non RFC1213 field
pub udp_lite_in_csum_errors: u64,
}
impl super::FromBufRead for Snmp6 {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut map = HashMap::new();
for line in r.lines() {
let line = expect!(line);
if line.is_empty() {
continue;
}
let mut s = line.split_whitespace();
let field = expect!(s.next(), "no field");
if field.starts_with("Icmp6InType") || field.starts_with("Icmp6OutType") {
continue;
}
let value = from_str!(u64, expect!(s.next(), "no value"));
map.insert(field.to_string(), value);
}
let snmp6 = Snmp6 {
ip_in_receives: expect!(map.remove("Ip6InReceives")),
ip_in_hdr_errors: expect!(map.remove("Ip6InHdrErrors")),
ip_in_too_big_errors: expect!(map.remove("Ip6InTooBigErrors")),
ip_in_no_routes: expect!(map.remove("Ip6InNoRoutes")),
ip_in_addr_errors: expect!(map.remove("Ip6InAddrErrors")),
ip_in_unknown_protos: expect!(map.remove("Ip6InUnknownProtos")),
ip_in_truncated_pkts: expect!(map.remove("Ip6InTruncatedPkts")),
ip_in_discards: expect!(map.remove("Ip6InDiscards")),
ip_in_delivers: expect!(map.remove("Ip6InDelivers")),
ip_out_forw_datagrams: expect!(map.remove("Ip6OutForwDatagrams")),
ip_out_requests: expect!(map.remove("Ip6OutRequests")),
ip_out_discards: expect!(map.remove("Ip6OutDiscards")),
ip_out_no_routes: expect!(map.remove("Ip6OutNoRoutes")),
ip_reasm_timeout: expect!(map.remove("Ip6ReasmTimeout")),
ip_reasm_reqds: expect!(map.remove("Ip6ReasmReqds")),
ip_reasm_oks: expect!(map.remove("Ip6ReasmOKs")),
ip_reasm_fails: expect!(map.remove("Ip6ReasmFails")),
ip_frag_oks: expect!(map.remove("Ip6FragOKs")),
ip_frag_fails: expect!(map.remove("Ip6FragFails")),
ip_frag_creates: expect!(map.remove("Ip6FragCreates")),
ip_in_mcast_pkts: expect!(map.remove("Ip6InMcastPkts")),
ip_out_mcast_pkts: expect!(map.remove("Ip6OutMcastPkts")),
ip_in_octets: expect!(map.remove("Ip6InOctets")),
ip_out_octets: expect!(map.remove("Ip6OutOctets")),
ip_in_mcast_octets: expect!(map.remove("Ip6InMcastOctets")),
ip_out_mcast_octets: expect!(map.remove("Ip6OutMcastOctets")),
ip_in_bcast_octets: expect!(map.remove("Ip6InBcastOctets")),
ip_out_bcast_octets: expect!(map.remove("Ip6OutBcastOctets")),
ip_in_no_ect_pkts: expect!(map.remove("Ip6InNoECTPkts")),
ip_in_ect1_pkts: expect!(map.remove("Ip6InECT1Pkts")),
ip_in_ect0_pkts: expect!(map.remove("Ip6InECT0Pkts")),
ip_in_ce_pkts: expect!(map.remove("Ip6InCEPkts")),
icmp_in_msgs: expect!(map.remove("Icmp6InMsgs")),
icmp_in_errors: expect!(map.remove("Icmp6InErrors")),
icmp_out_msgs: expect!(map.remove("Icmp6OutMsgs")),
icmp_out_errors: expect!(map.remove("Icmp6OutErrors")),
icmp_in_csum_errors: expect!(map.remove("Icmp6InCsumErrors")),
icmp_in_dest_unreachs: expect!(map.remove("Icmp6InDestUnreachs")),
icmp_in_pkt_too_bigs: expect!(map.remove("Icmp6InPktTooBigs")),
icmp_in_time_excds: expect!(map.remove("Icmp6InTimeExcds")),
icmp_in_parm_problem: expect!(map.remove("Icmp6InParmProblems")),
icmp_in_echos: expect!(map.remove("Icmp6InEchos")),
icmp_in_echo_replies: expect!(map.remove("Icmp6InEchoReplies")),
icmp_in_group_memb_queries: expect!(map.remove("Icmp6InGroupMembQueries")),
icmp_in_group_memb_responses: expect!(map.remove("Icmp6InGroupMembResponses")),
icmp_in_group_memb_reductions: expect!(map.remove("Icmp6InGroupMembReductions")),
icmp_in_router_solicits: expect!(map.remove("Icmp6InRouterSolicits")),
icmp_in_router_advertisements: expect!(map.remove("Icmp6InRouterAdvertisements")),
icmp_in_neighbor_solicits: expect!(map.remove("Icmp6InNeighborSolicits")),
icmp_in_neighbor_advertisements: expect!(map.remove("Icmp6InNeighborAdvertisements")),
icmp_in_redirects: expect!(map.remove("Icmp6InRedirects")),
icmp_in_mldv2_reports: expect!(map.remove("Icmp6InMLDv2Reports")),
icmp_out_dest_unreachs: expect!(map.remove("Icmp6OutDestUnreachs")),
icmp_out_pkt_too_bigs: expect!(map.remove("Icmp6OutPktTooBigs")),
icmp_out_time_excds: expect!(map.remove("Icmp6OutTimeExcds")),
icmp_out_parm_problems: expect!(map.remove("Icmp6OutParmProblems")),
icmp_out_echos: expect!(map.remove("Icmp6OutEchos")),
icmp_out_echo_replies: expect!(map.remove("Icmp6OutEchoReplies")),
icmp_out_group_memb_queries: expect!(map.remove("Icmp6OutGroupMembQueries")),
icmp_out_group_memb_responses: expect!(map.remove("Icmp6OutGroupMembResponses")),
icmp_out_group_memb_reductions: expect!(map.remove("Icmp6OutGroupMembReductions")),
icmp_out_router_solicits: expect!(map.remove("Icmp6OutRouterSolicits")),
icmp_out_router_advertisements: expect!(map.remove("Icmp6OutRouterAdvertisements")),
icmp_out_neighbor_solicits: expect!(map.remove("Icmp6OutNeighborSolicits")),
icmp_out_neighbor_advertisements: expect!(map.remove("Icmp6OutNeighborAdvertisements")),
icmp_out_redirects: expect!(map.remove("Icmp6OutRedirects")),
icmp_out_mldv2_reports: expect!(map.remove("Icmp6OutMLDv2Reports")),
//
// ignore ICMP numeric types
//
udp_in_datagrams: expect!(map.remove("Udp6InDatagrams")),
udp_no_ports: expect!(map.remove("Udp6NoPorts")),
udp_in_errors: expect!(map.remove("Udp6InErrors")),
udp_out_datagrams: expect!(map.remove("Udp6OutDatagrams")),
udp_rcvbuf_errors: expect!(map.remove("Udp6RcvbufErrors")),
udp_sndbuf_errors: expect!(map.remove("Udp6SndbufErrors")),
udp_in_csum_errors: expect!(map.remove("Udp6InCsumErrors")),
udp_ignored_multi: expect!(map.remove("Udp6IgnoredMulti")),
udp_lite_in_datagrams: expect!(map.remove("UdpLite6InDatagrams")),
udp_lite_no_ports: expect!(map.remove("UdpLite6NoPorts")),
udp_lite_in_errors: expect!(map.remove("UdpLite6InErrors")),
udp_lite_out_datagrams: expect!(map.remove("UdpLite6OutDatagrams")),
udp_lite_rcvbuf_errors: expect!(map.remove("UdpLite6RcvbufErrors")),
udp_lite_sndbuf_errors: expect!(map.remove("UdpLite6SndbufErrors")),
udp_lite_in_csum_errors: expect!(map.remove("UdpLite6InCsumErrors")),
};
if cfg!(test) {
assert!(map.is_empty(), "snmp6 map is not empty: {:#?}", map);
}
Ok(snmp6)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::IpAddr;
#[test]
fn test_parse_ipaddr() {
use std::str::FromStr;
let addr = parse_addressport_str("0100007F:1234", true).unwrap();
assert_eq!(addr.port(), 0x1234);
match addr.ip() {
IpAddr::V4(addr) => assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)),
_ => panic!("Not IPv4"),
}
// When you connect to [2a00:1450:4001:814::200e]:80 (ipv6.google.com) the entry with
// 5014002A14080140000000000E200000:0050 remote endpoint is created in /proc/net/tcp6
// on Linux 4.19.
let addr = parse_addressport_str("5014002A14080140000000000E200000:0050", true).unwrap();
assert_eq!(addr.port(), 80);
match addr.ip() {
IpAddr::V6(addr) => assert_eq!(addr, Ipv6Addr::from_str("2a00:1450:4001:814::200e").unwrap()),
_ => panic!("Not IPv6"),
}
// IPv6 test case from https://stackoverflow.com/questions/41940483/parse-ipv6-addresses-from-proc-net-tcp6-python-2-7/41948004#41948004
let addr = parse_addressport_str("B80D01200000000067452301EFCDAB89:0", true).unwrap();
assert_eq!(addr.port(), 0);
match addr.ip() {
IpAddr::V6(addr) => assert_eq!(addr, Ipv6Addr::from_str("2001:db8::123:4567:89ab:cdef").unwrap()),
_ => panic!("Not IPv6"),
}
let addr = parse_addressport_str("1234:1234", true);
assert!(addr.is_err());
}
#[test]
fn test_tcpstate_from() {
assert_eq!(TcpState::from_u8(0xA).unwrap(), TcpState::Listen);
}
}