Skip to main content

scx_utils/
netdev.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2
3// This software may be used and distributed according to the terms of the
4// GNU General Public License version 2.
5
6use std::collections::BTreeMap;
7use std::fs;
8use std::path::Path;
9
10use crate::misc::read_from_file;
11use crate::Cpumask;
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    original_irqs: BTreeMap<usize, Cpumask>,
21}
22
23impl NetDev {
24    pub fn iface(&self) -> &str {
25        &self.iface
26    }
27
28    pub fn node(&self) -> usize {
29        self.node
30    }
31
32    pub fn irq_hints(&self) -> &BTreeMap<usize, Cpumask> {
33        &self.irq_hints
34    }
35
36    pub fn update_irq_cpumask(&mut self, irq: usize, cpumask: Cpumask) {
37        if let Some(cur_cpumask) = self.irqs.get_mut(&irq) {
38            *cur_cpumask = cpumask;
39        }
40    }
41
42    pub fn apply_cpumasks(&self) -> Result<()> {
43        for (irq, cpumask) in self.irqs.iter() {
44            let irq_path = format!("/proc/irq/{irq}/smp_affinity");
45            fs::write(irq_path, format!("{cpumask:#x}"))?
46        }
47        Ok(())
48    }
49
50    pub fn restore_cpumasks(&self) -> Result<()> {
51        for (irq, cpumask) in self.original_irqs.iter() {
52            let irq_path = format!("/proc/irq/{irq}/smp_affinity");
53            fs::write(irq_path, format!("{cpumask:#x}"))?;
54        }
55        Ok(())
56    }
57}
58
59pub fn read_netdevs() -> Result<BTreeMap<String, NetDev>> {
60    let mut netdevs: BTreeMap<String, NetDev> = BTreeMap::new();
61
62    for entry in fs::read_dir("/sys/class/net")? {
63        let entry = entry?;
64        let iface = entry.file_name().to_string_lossy().into_owned();
65        let iface_path_raw = format!("/sys/class/net/{iface}/device/enable");
66        let iface_path = Path::new(&iface_path_raw);
67        let is_enabled = read_from_file(iface_path).unwrap_or(0_usize);
68        if is_enabled < 1 {
69            continue;
70        }
71        let raw_path = format!("/sys/class/net/{iface}/device/msi_irqs");
72        let msi_irqs_path = Path::new(&raw_path);
73        if !msi_irqs_path.exists() {
74            continue;
75        }
76
77        let node_path_raw = format!("/sys/class/net/{iface}/device/numa_node");
78        let node_path = Path::new(&node_path_raw);
79        let node = read_from_file(node_path).unwrap_or(0_usize);
80        let mut irqs = BTreeMap::new();
81        let mut irq_hints = BTreeMap::new();
82
83        for entry in fs::read_dir(msi_irqs_path)? {
84            let entry = entry.unwrap();
85            let irq = entry.file_name().to_string_lossy().into_owned();
86            if let Ok(irq) = irq.parse::<usize>() {
87                let irq_path_raw = format!("/proc/irq/{irq}");
88                let irq_path = Path::new(&irq_path_raw);
89                if !irq_path.exists() {
90                    continue;
91                }
92                let affinity_raw_path = format!("/proc/irq/{irq}/smp_affinity");
93                let smp_affinity_path = Path::new(&affinity_raw_path);
94                let smp_affinity = fs::read_to_string(smp_affinity_path)?
95                    .replace(",", "")
96                    .replace("\n", "");
97                let cpumask = Cpumask::from_str(&smp_affinity)?;
98                irqs.insert(irq, cpumask);
99
100                // affinity hints
101                let affinity_hint_raw_path = format!("/proc/irq/{irq}/affinity_hint");
102                let affinity_hint_path = Path::new(&affinity_hint_raw_path);
103                let affinity_hint = fs::read_to_string(affinity_hint_path)?
104                    .replace(",", "")
105                    .replace("\n", "");
106                let hint_cpumask = Cpumask::from_str(&affinity_hint)?;
107                irq_hints.insert(irq, hint_cpumask);
108            }
109        }
110        netdevs.insert(
111            iface.clone(),
112            NetDev {
113                iface,
114                node,
115                original_irqs: irqs.clone(),
116                irqs,
117                irq_hints,
118            },
119        );
120    }
121    Ok(netdevs)
122}