bpf_loader_lib/skeleton/preload/
mod.rs1use std::{collections::HashMap, sync::Arc};
8
9use crate::{
10 btf_container::BtfContainer,
11 elf_container::ElfContainer,
12 meta::{EunomiaObjectMeta, RunnerConfig},
13 skeleton::preload::{
14 attach::{attach_perf_event, attach_tc, attach_xdp, AttachLink},
15 section_loader::load_section_data_with_skel_value,
16 },
17};
18use anyhow::{anyhow, bail, Context, Result};
19use libbpf_rs::OpenObject;
20use log::debug;
21use object::{Object, ObjectSection};
22
23use super::{handle::PollingHandle, BpfSkeleton};
24pub(crate) mod attach;
25pub(crate) mod section_loader;
26pub struct PreLoadBpfSkeleton {
28 pub(crate) meta: EunomiaObjectMeta,
32 pub(crate) config_data: RunnerConfig,
36
37 pub(crate) bpf_object: OpenObject,
38
39 pub(crate) btf: BtfContainer,
41
42 pub(crate) map_value_sizes: HashMap<String, u32>,
45
46 pub(crate) raw_elf: ElfContainer,
47}
48
49impl PreLoadBpfSkeleton {
50 pub fn load_and_attach(mut self) -> Result<BpfSkeleton> {
56 debug!(
61 "Section names of ELF: {:?}",
62 self.raw_elf
63 .borrow_elf()
64 .sections()
65 .map(|v| v.name().map(|t| t.to_string()))
66 .collect::<Vec<_>>()
67 );
68
69 for section in self.meta.bpf_skel.data_sections.iter() {
71 debug!("Loading section: {:?}", section);
72 let map_meta = match section.name.as_str() {
73 ".rodata" => self
74 .meta
75 .bpf_skel
76 .find_map_by_ident("rodata")
77 .ok_or_else(|| {
78 anyhow!("Failed to find map with ident `rodata` for section .rodata")
79 })?,
80 ".bss" => self.meta.bpf_skel.find_map_by_ident("bss").ok_or_else(|| {
81 anyhow!("Failed to find map with ident `bss` for section .bss")
82 })?,
83 s => bail!("Unsupported section: {}", s),
84 };
85 let map_name = map_meta.name.as_str();
86 let map = self.bpf_object.map_mut(map_name).ok_or_else(|| {
87 anyhow!(
88 "Map named `{}` doesn't exist, cannot map section `{}`",
89 map_name,
90 section.name
91 )
92 })?;
93 let buffer_size = *self
95 .map_value_sizes
96 .get(map_name)
97 .ok_or_else(|| anyhow!("Map name {} not found in value sizes", map_name))?
98 as usize;
99 debug!("Buffer size: {}", buffer_size);
100 let mut buffer = if let Some(v) = self
101 .raw_elf
102 .borrow_elf()
103 .section_data_by_name(§ion.name)
104 {
105 debug!("Using buffer from ELF");
106 v.to_vec()
107 } else {
108 debug!("Using empty buffer");
109 vec![0; buffer_size]
110 };
111 if buffer.len() < buffer_size {
112 buffer.resize(buffer_size, 0);
114 }
115 debug!("Buffer before filling: {:?}", buffer);
116 load_section_data_with_skel_value(self.btf.borrow_btf(), section, &mut buffer)
117 .with_context(|| anyhow!("Failed to load section {}", section.name))?;
118 debug!("Loaded buffer: {:?}", buffer);
119 map.set_initial_value(&buffer[..])
120 .map_err(|e| anyhow!("Failed to set initial value of map `{}`: {}", map_name, e))?;
121 }
122
123 let mut bpf_object = self
124 .bpf_object
125 .load()
126 .with_context(|| anyhow!("Failed to load bpf object"))?;
127 let mut not_attached = vec![];
129 let mut links = vec![];
130 for prog_meta in self.meta.bpf_skel.progs.iter() {
131 let bpf_prog = bpf_object
132 .prog_mut(&prog_meta.name)
133 .ok_or_else(|| anyhow!("Program named `{}` not found in libbpf", prog_meta.name))?;
134 match bpf_prog.attach() {
135 Ok(link) => links.push(AttachLink::BpfLink(link)),
136 Err(_) if errno::errno().0 == 95 => {
138 not_attached.push(prog_meta);
140 continue;
141 }
142 Err(err) => bail!("Failed to attach program `{}`: {}", prog_meta.name, err),
143 };
144 }
145 for prog_meta in not_attached.into_iter() {
146 let bpf_prog = bpf_object
147 .prog_mut(&prog_meta.name)
148 .ok_or_else(|| anyhow!("Program named `{}` not found", prog_meta.name))?;
149 match bpf_prog.section() {
150 "tc" => links.push(attach_tc(bpf_prog, prog_meta).with_context(|| {
151 anyhow!("Failed to attach tc program `{}`", prog_meta.name)
152 })?),
153 "xdp" => links.push(attach_xdp(bpf_prog, prog_meta).with_context(|| {
154 anyhow!("Failed to attach xdp program `{}`", prog_meta.name)
155 })?),
156 "perf_event" => {
157 let mut perf_links =
158 attach_perf_event(bpf_prog, prog_meta).with_context(|| {
159 anyhow!("Failed to attach perf event program `{}`", prog_meta.name)
160 })?;
161 links.append(&mut perf_links);
162 }
163 s => bail!("Unsupported attach type: {}", s),
164 }
165 }
166 Ok(BpfSkeleton {
167 handle: PollingHandle::new(),
168 meta: self.meta,
169 config_data: self.config_data,
170 btf: Arc::new(self.btf),
171 links,
172 prog: bpf_object,
173 })
174 }
175}
176
177#[cfg(test)]
178#[cfg(not(feature = "no-load-bpf-tests"))]
179mod tests {
180 use crate::{
181 meta::ComposedObject, skeleton::builder::BpfSkeletonBuilder, tests::get_assets_dir,
182 };
183
184 #[test]
185 fn test_load_and_attach() {
186 let skel: ComposedObject = serde_json::from_str(
187 &std::fs::read_to_string(get_assets_dir().join("bootstrap.json")).unwrap(),
188 )
189 .unwrap();
190 let pre_load_skel = BpfSkeletonBuilder::from_json_package(&skel, None)
191 .build()
192 .unwrap();
193 let loaded = pre_load_skel.load_and_attach().unwrap();
194 let prog = loaded.prog;
195 for map_meta in skel.meta.bpf_skel.maps.iter() {
196 let _map_bpf = prog.map(map_meta.name.as_str()).unwrap();
197 }
198 for prog_meta in skel.meta.bpf_skel.progs.iter() {
199 let prog_bpf = prog.prog(&prog_meta.name).unwrap();
200 assert_eq!(prog_bpf.section(), prog_meta.attach);
201 }
202 assert_eq!(loaded.links.len(), skel.meta.bpf_skel.progs.len());
203 }
204}