bpf/
common.rs

1// SPDX-License-Identifier: Apache-2.0
2use std::collections::HashSet;
3use std::path::Path;
4
5use anyhow::{anyhow, Context, Result};
6use libbpf_rs::{skel::Skel, Link, MapCore, MapHandle, ProgramMut};
7use tracing::trace;
8
9type InodeNumber = u64;
10
11pub struct PinnedLink {
12    pub link: Link,
13    pub inode: InodeNumber,
14}
15
16/// Attach and pin all programs for a skeleton
17pub fn attach_pin_programs(
18    skel: &mut dyn Skel,
19    pin_dir: &Path,
20    prog_name_filter: HashSet<String>,
21) -> Result<Vec<PinnedLink>> {
22    // Attach & pin
23    let mut pinned_links: Vec<PinnedLink> = Vec::new();
24
25    for prog in skel.object_mut().progs_mut() {
26        let prog_name = prog
27            .name()
28            .to_str()
29            .context("Bad program name")?
30            .to_string();
31        if !prog_name_filter.contains(prog_name.as_str()) {
32            pinned_links.push(attach_pin(prog, &prog_name, pin_dir)?);
33        }
34    }
35    Ok(pinned_links)
36}
37
38/// Attach and pin all programs
39pub fn attach_pin(prog: ProgramMut, prog_name: &str, pin_dir: &Path) -> Result<PinnedLink> {
40    let pin_path = pin_dir.join(prog_name);
41
42    // Attach program
43    // Note: Some eBPF programs (XDP) require an argument.
44    //       These program types will fail to attach with this implementation.
45    let mut link = prog
46        .attach()
47        .context(format!("Failed to attach {prog_name}"))?;
48
49    // Pin program
50    link.pin(&pin_path)
51        .context(format!("Failed to pin {prog_name}"))?;
52
53    trace!(
54        "Attached program {} and pinned to path {}",
55        prog_name,
56        pin_path.to_string_lossy()
57    );
58
59    // Save link and inode info
60    let pin_path_inode = nix::sys::stat::stat(&pin_path)?.st_ino;
61
62    Ok(PinnedLink {
63        link,
64        inode: pin_path_inode,
65    })
66}
67
68/// Helper function to get a named map from a skeleton or return an Err
69pub fn get_map(name: &str, skel: &dyn Skel) -> Result<MapHandle> {
70    for map in skel.object().maps() {
71        if name == map.name() {
72            return Ok(MapHandle::try_from(&map)?);
73        }
74    }
75    Err(anyhow!("{name} map not found in skeleton"))
76}
77
78/// Helper function to get a named program from a skeleton or return an Err
79pub fn get_prog<'a>(name: &str, skel: &'a mut dyn Skel) -> Result<ProgramMut<'a>> {
80    for prog in skel.object_mut().progs_mut() {
81        if prog.name() == name {
82            return Ok(prog);
83        }
84    }
85    Err(anyhow!("{name} program not found in skeleton"))
86}