Skip to content
This repository was archived by the owner on Feb 28, 2024. It is now read-only.

Commit 310352b

Browse files
authored
Merge pull request #45 from redcanaryco/fix-default-num-cpus
Fix default num cpus
2 parents 4e9f901 + 9c53032 commit 310352b

File tree

4 files changed

+134
-90
lines changed

4 files changed

+134
-90
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description = "A pure-Rust library for managing eBPF programs."
44
homepage = "https://github.com/redcanaryco/oxidebpf"
55
repository = "https://github.com/redcanaryco/oxidebpf"
66
readme = "README.md"
7-
version = "0.1.2"
7+
version = "0.1.3"
88
license = "BSD-3-Clause"
99
keywords = ["eBPF", "BPF", "linux"]
1010
categories = ["config", "data-structures", "os::linux-apis", "parsing"]
@@ -14,6 +14,7 @@ authors = [
1414
"Rafael Ortiz <rafael.ortiz@redcanary.com>",
1515
"Dave Bogle <dave.bogle@redcanary.com>",
1616
"Andrés Medina <andres.medina@redcanary.com>",
17+
"Vince Bundage <vince.bundage@redcanary.com>"
1718
]
1819
edition = "2021"
1920

src/cpu_info.rs

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use slog::info;
2+
3+
use crate::{OxidebpfError, LOGGER};
4+
5+
pub fn online() -> Result<Vec<i32>, OxidebpfError> {
6+
let cpu_string = std::fs::read_to_string("/sys/devices/system/cpu/online").map_err(|e| {
7+
info!(
8+
LOGGER.0,
9+
"cpu_info::online(); could not read /sys/devices/system/cpu/online; error: {:?}", e
10+
);
11+
OxidebpfError::FileIOError
12+
})?;
13+
14+
process_cpu_string(&cpu_string)
15+
}
16+
17+
pub fn max_possible_index() -> Result<usize, OxidebpfError> {
18+
let cpu_string = std::fs::read_to_string("/sys/devices/system/cpu/possible").map_err(
19+
|e| {
20+
info!(
21+
LOGGER.0,
22+
"cpu_info::max_possible_index(); could not read /sys/devices/system/cpu/possible; error: {:?}", e
23+
);
24+
OxidebpfError::FileIOError
25+
},
26+
)?;
27+
28+
max_index(&cpu_string)
29+
}
30+
31+
fn max_index(cpu_string: &str) -> Result<usize, OxidebpfError> {
32+
let last = cpu_string
33+
.trim()
34+
.split(',')
35+
.last()
36+
.ok_or(OxidebpfError::CpuOnlineFormatError)?;
37+
38+
let last_index = match last.split_once('-') {
39+
None => last,
40+
Some((_, b)) => b,
41+
};
42+
43+
last_index
44+
.parse()
45+
.map_err(|_| OxidebpfError::CpuOnlineFormatError)
46+
}
47+
48+
fn process_cpu_string(cpu_string: &str) -> Result<Vec<i32>, OxidebpfError> {
49+
let mut cpus = vec![];
50+
51+
for sublist in cpu_string.trim().split(',') {
52+
if sublist.contains('-') {
53+
let pair: Vec<&str> = sublist.split('-').collect();
54+
if pair.len() != 2 {
55+
info!(
56+
LOGGER.0,
57+
"process_cpu_string(); cpu online formatting error: {}", cpu_string
58+
);
59+
return Err(OxidebpfError::CpuOnlineFormatError);
60+
}
61+
62+
// we checked the length above so indexing is OK
63+
let from: i32 = pair[0].parse().map_err(|e| {
64+
info!(
65+
LOGGER.0,
66+
"process_cpu_string(); cpu online i32 parse error; pair: {:?}; error: {:?}",
67+
pair,
68+
e
69+
);
70+
OxidebpfError::CpuOnlineFormatError
71+
})?;
72+
let to: i32 = pair[1].parse().map_err(|e| {
73+
info!(
74+
LOGGER.0,
75+
"process_cpu_string(); cpu online i32 parse error; pair: {:?}; error: {:?}",
76+
pair,
77+
e
78+
);
79+
OxidebpfError::CpuOnlineFormatError
80+
})?;
81+
82+
cpus.extend(from..=to)
83+
} else {
84+
cpus.push(sublist.trim().parse().map_err(|e| {
85+
info!(
86+
LOGGER.0,
87+
"process_cpu_string(); sublist number parsing error; sublist: {:?}; error: {:?}", sublist, e
88+
);
89+
OxidebpfError::NumberParserError
90+
})?);
91+
}
92+
}
93+
94+
Ok(cpus)
95+
}
96+
97+
#[cfg(test)]
98+
mod tests {
99+
use super::*;
100+
101+
#[test]
102+
fn single_range() {
103+
let result = max_index("0-127").expect("did not parse cpu_string");
104+
assert_eq!(result, 127);
105+
}
106+
107+
#[test]
108+
fn single_number() {
109+
let result = max_index("4").expect("did not parse cpu_string");
110+
assert_eq!(result, 4);
111+
}
112+
113+
#[test]
114+
fn combination() {
115+
let result = max_index("0,3-5,8\n").expect("did not parse cpu_string");
116+
assert_eq!(result, 8);
117+
}
118+
119+
#[test]
120+
fn test_cpu_formatter() {
121+
assert_eq!(vec![0], process_cpu_string("0").unwrap());
122+
assert_eq!(vec![0, 1, 2], process_cpu_string("0-2").unwrap());
123+
assert_eq!(vec![0, 3, 4, 5, 8], process_cpu_string("0,3-5,8").unwrap());
124+
}
125+
}

src/lib.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
mod blueprint;
1616
mod bpf;
17+
mod cpu_info;
1718
mod debugfs;
1819
mod error;
1920
mod maps;
@@ -55,8 +56,6 @@ use libc::{c_int, pid_t};
5556
use slog::{crit, error, info, o, Logger};
5657
use slog_atomic::{AtomicSwitch, AtomicSwitchCtrl};
5758

58-
use crate::maps::get_cpus;
59-
6059
lazy_static! {
6160
/// The slog Logger for the oxidebpf library. You can change the destination
6261
/// by accessing the drain control with `LOGGER.1.set(your_new_drain)`.
@@ -475,7 +474,7 @@ impl<'a> Program<'a> {
475474
let is_return = self.kind == Some(ProgramType::Uretprobe);
476475
let pid = self.pid.unwrap_or(-1);
477476

478-
maps::get_cpus()?
477+
cpu_info::online()?
479478
.into_iter()
480479
.flat_map(|cpu| {
481480
self.attach_points
@@ -812,6 +811,8 @@ impl ProgramVersion<'_> {
812811

813812
let mut perfmap_opts = None;
814813

814+
let perfmap_entries = cpu_info::max_possible_index()? as u32 + 1;
815+
815816
for program_object in matching_blueprints.iter_mut() {
816817
for name in program_object.required_maps().iter() {
817818
let map = program_blueprint
@@ -831,7 +832,7 @@ impl ProgramVersion<'_> {
831832
match map.definition.map_type {
832833
bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY => {
833834
if map.definition.max_entries == 0 {
834-
map.definition.max_entries = get_cpus()?.len() as u32;
835+
map.definition.max_entries = perfmap_entries
835836
};
836837

837838
let fd = unsafe {

src/maps/mod.rs

+2-85
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::perf::PerfEventAttr;
2222
use slog::info;
2323
use std::fmt::{Debug, Display, Formatter};
2424

25-
use crate::LOGGER;
25+
use crate::{cpu_info, LOGGER};
2626

2727
#[repr(C)]
2828
#[derive(Clone, Copy)]
@@ -45,75 +45,6 @@ pub struct PerfEventSample {
4545
pub data: Vec<u8>,
4646
}
4747

48-
pub(crate) fn process_cpu_string(cpu_string: String) -> Result<Vec<i32>, OxidebpfError> {
49-
let mut cpus = vec![];
50-
51-
for sublist in cpu_string.trim().split(',') {
52-
if sublist.contains('-') {
53-
let pair: Vec<&str> = sublist.split('-').collect();
54-
if pair.len() != 2 {
55-
info!(
56-
LOGGER.0,
57-
"process_cpu_string(); cpu online formatting error: {}", cpu_string
58-
);
59-
return Err(OxidebpfError::CpuOnlineFormatError);
60-
}
61-
62-
// we checked the length above so indexing is OK
63-
let from: i32 = pair[0].parse().map_err(|e| {
64-
info!(
65-
LOGGER.0,
66-
"process_cpu_string(); cpu online i32 parse error; pair: {:?}; error: {:?}",
67-
pair,
68-
e
69-
);
70-
OxidebpfError::CpuOnlineFormatError
71-
})?;
72-
let to: i32 = pair[1].parse().map_err(|e| {
73-
info!(
74-
LOGGER.0,
75-
"process_cpu_string(); cpu online i32 parse error; pair: {:?}; error: {:?}",
76-
pair,
77-
e
78-
);
79-
OxidebpfError::CpuOnlineFormatError
80-
})?;
81-
82-
cpus.extend(from..=to)
83-
} else {
84-
cpus.push(sublist.trim().parse().map_err(|e| {
85-
info!(
86-
LOGGER.0,
87-
"process_cpu_string(); sublist number parsing error; sublist: {:?}; error: {:?}", sublist, e
88-
);
89-
OxidebpfError::NumberParserError
90-
})?);
91-
}
92-
}
93-
94-
Ok(cpus)
95-
}
96-
97-
pub(crate) fn get_cpus() -> Result<Vec<i32>, OxidebpfError> {
98-
let cpu_string = String::from_utf8(std::fs::read("/sys/devices/system/cpu/online").map_err(
99-
|e| {
100-
info!(
101-
LOGGER.0,
102-
"get_cpus(); could not read /sys/devices/system/cpu/online; error: {:?}", e
103-
);
104-
OxidebpfError::FileIOError
105-
},
106-
)?)
107-
.map_err(|e| {
108-
info!(
109-
LOGGER.0,
110-
"get_cpus(); utf8 string conversion error while getting cpus; error: {:?}", e
111-
);
112-
OxidebpfError::Utf8StringConversionError
113-
})?;
114-
process_cpu_string(cpu_string)
115-
}
116-
11748
pub(crate) enum PerfEvent {
11849
Sample(PerfEventSample),
11950
Lost(u64),
@@ -333,7 +264,7 @@ impl PerfMap {
333264
let mmap_size = page_size * (page_count + 1);
334265

335266
let mut loaded_perfmaps = Vec::<PerfMap>::new();
336-
for cpuid in get_cpus()?.iter() {
267+
for cpuid in cpu_info::online()?.iter() {
337268
let fd: RawFd = crate::perf::syscall::perf_event_open(&event_attr, -1, *cpuid, -1, 0)?;
338269
let base_ptr: *mut _;
339270
base_ptr = unsafe {
@@ -956,7 +887,6 @@ fn lte_power_of_two(n: usize) -> usize {
956887
#[cfg(test)]
957888
mod map_tests {
958889
use crate::error::OxidebpfError;
959-
use crate::maps::process_cpu_string;
960890
use crate::maps::RWMap;
961891
use crate::maps::{ArrayMap, BpfHashMap};
962892
use nix::errno::Errno;
@@ -970,19 +900,6 @@ mod map_tests {
970900
seed_time.as_millis() as u64
971901
}
972902

973-
#[test]
974-
fn test_cpu_formatter() {
975-
assert_eq!(vec![0], process_cpu_string("0".to_string()).unwrap());
976-
assert_eq!(
977-
vec![0, 1, 2],
978-
process_cpu_string("0-2".to_string()).unwrap()
979-
);
980-
assert_eq!(
981-
vec![0, 3, 4, 5, 8],
982-
process_cpu_string("0,3-5,8".to_string()).unwrap()
983-
);
984-
}
985-
986903
// Test the normal behavior of the array map type
987904
//
988905
// This test simply writes to all the entries in the map and then tries to read

0 commit comments

Comments
 (0)