Skip to content

Commit fcdc85e

Browse files
author
Michael Schleicher
committed
feat: ✨ Use kernel version to determine if /proc/net/udp drops column can be read
Kernels prior to 2.6.27 do not provide a drops column for /proc/net/udp therefore a check is introduced to validate the current kernel version before reading the column Add kernel version to SystemInfoInterface
1 parent faebad1 commit fcdc85e

File tree

4 files changed

+64
-16
lines changed

4 files changed

+64
-16
lines changed

procfs-core/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ pub trait SystemInfoInterface {
257257
fn page_size(&self) -> u64;
258258
/// Whether the system is little endian (true) or big endian (false).
259259
fn is_little_endian(&self) -> bool;
260+
fn kernel_version(&self) -> ProcResult<KernelVersion>;
260261

261262
#[cfg(feature = "chrono")]
262263
fn boot_time(&self) -> ProcResult<chrono::DateTime<chrono::Local>> {
@@ -277,6 +278,7 @@ pub struct ExplicitSystemInfo {
277278
pub ticks_per_second: u64,
278279
pub page_size: u64,
279280
pub is_little_endian: bool,
281+
pub kernel_version: KernelVersion,
280282
}
281283

282284
impl SystemInfoInterface for ExplicitSystemInfo {
@@ -295,6 +297,10 @@ impl SystemInfoInterface for ExplicitSystemInfo {
295297
fn is_little_endian(&self) -> bool {
296298
self.is_little_endian
297299
}
300+
301+
fn kernel_version(&self) -> ProcResult<KernelVersion> {
302+
Ok(self.kernel_version)
303+
}
298304
}
299305

300306
/// Values which can provide an output given the [SystemInfo].

procfs-core/src/net.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
//!
77
//! This module corresponds to the `/proc/net` directory and contains various information about the
88
//! networking layer.
9-
use crate::ProcResult;
109
use crate::{build_internal_error, expect, from_iter, from_str};
11-
use std::collections::HashMap;
12-
10+
use crate::{KernelVersion, ProcResult};
1311
use bitflags::bitflags;
12+
use std::collections::HashMap;
1413
use std::io::BufRead;
1514
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
1615
use std::{path::PathBuf, str::FromStr};
@@ -296,9 +295,15 @@ impl super::FromBufReadSI for UdpNetEntries {
296295
let uid = from_str!(u32, expect!(s.next(), "udp::uid"));
297296
s.next(); // skip timeout
298297
let inode = expect!(s.next(), "udp::inode");
299-
s.next(); // skip ref
300-
s.next(); // skip pointer
301-
let drops = expect!(s.next(), "udp::drops");
298+
299+
let drops = match system_info.kernel_version() {
300+
Ok(version) if version >= KernelVersion::new(2, 6, 27) => {
301+
s.next(); // skip ref
302+
s.next(); // skip pointer
303+
expect!(s.next(), "udp::drops")
304+
}
305+
_ => "0", // Fallback if the kernel version does not support the drops column or the kernel version could not be read
306+
};
302307

303308
vec.push(UdpNetEntry {
304309
local_address: parse_addressport_str(local_address, system_info.is_little_endian())?,
@@ -1735,24 +1740,51 @@ UdpLite: 0 0 0 0 0 0 0 0 0
17351740
}
17361741

17371742
#[test]
1738-
fn test_udp_drops_debian_12() {
1739-
let data = r#" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops
1740-
624: 00000000:D77C 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719666 2 000000008fba5196 0
1741-
824: 00000000:0044 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 14796 2 0000000051381d39 0
1742-
918: 00000000:00A2 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719670 2 0000000048ae40a7 0
1743-
1270: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719665 2 00000000357eb7c3 0
1744-
1357: 00000000:AA59 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719668 2 000000000ed7b854 0"#;
1743+
fn test_udp_drops_debian_kernel_version_greater_2_6_27() {
1744+
let expected_drops = 42;
1745+
let data = format!(
1746+
r#" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops
1747+
1270: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719665 2 00000000357eb7c3 {expected_drops}"#
1748+
);
17451749
let r = std::io::Cursor::new(data.as_bytes());
17461750
use crate::FromBufReadSI;
1747-
let res = UdpNetEntries::from_buf_read(
1751+
let entries = UdpNetEntries::from_buf_read(
17481752
r,
17491753
&crate::ExplicitSystemInfo {
17501754
boot_time_secs: 0,
17511755
ticks_per_second: 0,
17521756
page_size: 0,
17531757
is_little_endian: true,
1758+
kernel_version: "2.6.27".parse().unwrap(),
17541759
},
1760+
)
1761+
.unwrap();
1762+
let entry = entries.0.first().unwrap();
1763+
1764+
assert_eq!(entry.drops, expected_drops)
1765+
}
1766+
1767+
#[test]
1768+
fn test_udp_drops_debian_kernel_version_smaller_2_6_27() {
1769+
let data = format!(
1770+
r#" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
1771+
1270: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719665"#
17551772
);
1756-
assert!(res.is_ok())
1773+
let r = std::io::Cursor::new(data.as_bytes());
1774+
use crate::FromBufReadSI;
1775+
let entries = UdpNetEntries::from_buf_read(
1776+
r,
1777+
&crate::ExplicitSystemInfo {
1778+
boot_time_secs: 0,
1779+
ticks_per_second: 0,
1780+
page_size: 0,
1781+
is_little_endian: true,
1782+
kernel_version: "2.6.26".parse().unwrap(),
1783+
},
1784+
)
1785+
.unwrap();
1786+
let entry = entries.0.first().unwrap();
1787+
1788+
assert_eq!(entry.drops, 0)
17571789
}
17581790
}

procfs/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ impl SystemInfoInterface for LocalSystemInfo {
9595
fn is_little_endian(&self) -> bool {
9696
u16::from_ne_bytes([0, 1]).to_le_bytes() == [0, 1]
9797
}
98+
99+
fn kernel_version(&self) -> ProcResult<procfs_core::KernelVersion> {
100+
KernelVersion::cached().map(Into::into)
101+
}
98102
}
99103

100104
const LOCAL_SYSTEM_INFO: LocalSystemInfo = LocalSystemInfo;

procfs/src/sys/kernel/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl Version {
6666
Self {
6767
major,
6868
minor,
69-
patch: u16::from_ne_bytes([lo, hi])
69+
patch: u16::from_ne_bytes([lo, hi]),
7070
}
7171
}
7272

@@ -145,6 +145,12 @@ impl cmp::PartialOrd for Version {
145145
}
146146
}
147147

148+
impl From<Version> for procfs_core::KernelVersion {
149+
fn from(value: Version) -> Self {
150+
Self::new(value.major, value.minor, value.patch)
151+
}
152+
}
153+
148154
/// Represents a kernel type
149155
#[derive(Debug, Clone, Eq, PartialEq)]
150156
pub struct Type {

0 commit comments

Comments
 (0)