1use std::collections::BTreeMap;
7use std::fs;
8use std::path::Path;
9
10use crate::Cpumask;
11use crate::misc::read_from_file;
12use anyhow::Result;
13
14#[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
15pub struct NetDev {
16 iface: String,
17 node: usize,
18 pub irqs: BTreeMap<usize, Cpumask>,
19 irq_hints: BTreeMap<usize, Cpumask>,
20}
21
22impl NetDev {
23 pub fn iface(&self) -> &str {
24 &self.iface
25 }
26
27 pub fn node(&self) -> usize {
28 self.node
29 }
30
31 pub fn irq_hints(&self) -> &BTreeMap<usize, Cpumask> {
32 &self.irq_hints
33 }
34
35 pub fn update_irq_cpumask(&mut self, irq: usize, cpumask: Cpumask) {
36 if let Some(cur_cpumask) = self.irqs.get_mut(&irq) {
37 *cur_cpumask = cpumask;
38 }
39 }
40
41 pub fn apply_cpumasks(&self) -> Result<()> {
42 for (irq, cpumask) in self.irqs.iter() {
43 let irq_path = format!("/proc/irq/{}/smp_affinity", irq);
44 fs::write(irq_path, format!("{:#x}", cpumask))?
45 }
46 Ok(())
47 }
48}
49
50pub fn read_netdevs() -> Result<BTreeMap<String, NetDev>> {
51 let mut netdevs: BTreeMap<String, NetDev> = BTreeMap::new();
52
53 for entry in fs::read_dir("/sys/class/net")? {
54 let entry = entry?;
55 let iface = entry.file_name().to_string_lossy().into_owned();
56 let iface_path_raw = format!("/sys/class/net/{}/device/enable", iface);
57 let iface_path = Path::new(&iface_path_raw);
58 let is_enabled = read_from_file(iface_path).unwrap_or(0_usize);
59 if is_enabled < 1 {
60 continue;
61 }
62 let raw_path = format!("/sys/class/net/{}/device/msi_irqs", iface);
63 let msi_irqs_path = Path::new(&raw_path);
64 if !msi_irqs_path.exists() {
65 continue;
66 }
67
68 let node_path_raw = format!("/sys/class/net/{}/device/numa_node", iface);
69 let node_path = Path::new(&node_path_raw);
70 let node = read_from_file(node_path).unwrap_or(0_usize);
71 let mut irqs = BTreeMap::new();
72 let mut irq_hints = BTreeMap::new();
73
74 for entry in fs::read_dir(msi_irqs_path)? {
75 let entry = entry.unwrap();
76 let irq = entry.file_name().to_string_lossy().into_owned();
77 if let Ok(irq) = irq.parse::<usize>() {
78 let affinity_raw_path = format!("/proc/irq/{}/smp_affinity", irq);
79 let smp_affinity_path = Path::new(&affinity_raw_path);
80 let smp_affinity = fs::read_to_string(smp_affinity_path)?
81 .replace(",", "")
82 .replace("\n", "");
83 let cpumask = Cpumask::from_str(&smp_affinity)?;
84 irqs.insert(irq, cpumask);
85
86 let affinity_hint_raw_path = format!("/proc/irq/{}/affinity_hint", irq);
88 let affinity_hint_path = Path::new(&affinity_hint_raw_path);
89 let affinity_hint = fs::read_to_string(affinity_hint_path)?
90 .replace(",", "")
91 .replace("\n", "");
92 let hint_cpumask = Cpumask::from_str(&affinity_hint)?;
93 irq_hints.insert(irq, hint_cpumask);
94 }
95 }
96 netdevs.insert(
97 iface.clone(),
98 NetDev {
99 iface,
100 node,
101 irqs,
102 irq_hints,
103 },
104 );
105 }
106 Ok(netdevs)
107}