1use 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
16pub fn attach_pin_programs(
18 skel: &mut dyn Skel,
19 pin_dir: &Path,
20 prog_name_filter: HashSet<String>,
21) -> Result<Vec<PinnedLink>> {
22 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
38pub fn attach_pin(prog: ProgramMut, prog_name: &str, pin_dir: &Path) -> Result<PinnedLink> {
40 let pin_path = pin_dir.join(prog_name);
41
42 let mut link = prog
46 .attach()
47 .context(format!("Failed to attach {prog_name}"))?;
48
49 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 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
68pub 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
78pub 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}