1 use core::ffi::c_void; 2 use std::ffi::CStr; 3 use std::ffi::CString; 4 use std::ffi::OsStr; 5 use std::mem; 6 use std::os::unix::ffi::OsStrExt as _; 7 use std::path::Path; 8 use std::ptr; 9 use std::ptr::addr_of; 10 use std::ptr::NonNull; 11 12 use crate::map::map_fd; 13 use crate::set_print; 14 use crate::util; 15 use crate::util::validate_bpf_ret; 16 use crate::Btf; 17 use crate::ErrorExt as _; 18 use crate::Map; 19 use crate::MapMut; 20 use crate::OpenMap; 21 use crate::OpenMapMut; 22 use crate::OpenProgram; 23 use crate::OpenProgramMut; 24 use crate::PrintLevel; 25 use crate::Program; 26 use crate::ProgramMut; 27 use crate::Result; 28 29 30 /// An iterator over the maps in a BPF object. 31 #[derive(Debug)] 32 pub struct MapIter<'obj> { 33 obj: &'obj libbpf_sys::bpf_object, 34 last: *mut libbpf_sys::bpf_map, 35 } 36 37 impl<'obj> MapIter<'obj> { 38 /// Create a new iterator over the maps of the given BPF object. new(obj: &'obj libbpf_sys::bpf_object) -> Self39 pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self { 40 Self { 41 obj, 42 last: ptr::null_mut(), 43 } 44 } 45 } 46 47 impl Iterator for MapIter<'_> { 48 type Item = NonNull<libbpf_sys::bpf_map>; 49 next(&mut self) -> Option<Self::Item>50 fn next(&mut self) -> Option<Self::Item> { 51 self.last = unsafe { libbpf_sys::bpf_object__next_map(self.obj, self.last) }; 52 NonNull::new(self.last) 53 } 54 } 55 56 57 /// An iterator over the programs in a BPF object. 58 #[derive(Debug)] 59 pub struct ProgIter<'obj> { 60 obj: &'obj libbpf_sys::bpf_object, 61 last: *mut libbpf_sys::bpf_program, 62 } 63 64 impl<'obj> ProgIter<'obj> { 65 /// Create a new iterator over the programs of the given BPF object. new(obj: &'obj libbpf_sys::bpf_object) -> Self66 pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self { 67 Self { 68 obj, 69 last: ptr::null_mut(), 70 } 71 } 72 } 73 74 impl Iterator for ProgIter<'_> { 75 type Item = NonNull<libbpf_sys::bpf_program>; 76 next(&mut self) -> Option<Self::Item>77 fn next(&mut self) -> Option<Self::Item> { 78 self.last = unsafe { libbpf_sys::bpf_object__next_program(self.obj, self.last) }; 79 NonNull::new(self.last) 80 } 81 } 82 83 84 /// A trait implemented for types that are thin wrappers around `libbpf` types. 85 /// 86 /// The trait provides access to the underlying `libbpf` (or `libbpf-sys`) 87 /// object. In many cases, this enables direct usage of `libbpf-sys` 88 /// functionality when higher-level bindings are not yet provided by this crate. 89 pub trait AsRawLibbpf { 90 /// The underlying `libbpf` type. 91 type LibbpfType; 92 93 /// Retrieve the underlying `libbpf` object. 94 /// 95 /// # Warning 96 /// By virtue of working with a mutable raw pointer this method effectively 97 /// circumvents mutability and liveness checks. While by-design, usage is 98 /// meant as an escape-hatch more than anything else. If you find yourself 99 /// making use of it, please consider discussing your workflow with crate 100 /// maintainers to see if it would make sense to provide safer wrappers. as_libbpf_object(&self) -> NonNull<Self::LibbpfType>101 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType>; 102 } 103 104 /// Builder for creating an [`OpenObject`]. Typically the entry point into libbpf-rs. 105 #[derive(Debug)] 106 pub struct ObjectBuilder { 107 name: Option<CString>, 108 pin_root_path: Option<CString>, 109 110 opts: libbpf_sys::bpf_object_open_opts, 111 } 112 113 impl Default for ObjectBuilder { default() -> Self114 fn default() -> Self { 115 let opts = libbpf_sys::bpf_object_open_opts { 116 sz: mem::size_of::<libbpf_sys::bpf_object_open_opts>() as libbpf_sys::size_t, 117 object_name: ptr::null(), 118 relaxed_maps: false, 119 pin_root_path: ptr::null(), 120 kconfig: ptr::null(), 121 btf_custom_path: ptr::null(), 122 kernel_log_buf: ptr::null_mut(), 123 kernel_log_size: 0, 124 kernel_log_level: 0, 125 ..Default::default() 126 }; 127 Self { 128 name: None, 129 pin_root_path: None, 130 opts, 131 } 132 } 133 } 134 135 impl ObjectBuilder { 136 /// Override the generated name that would have been inferred from the constructor. name<T: AsRef<str>>(&mut self, name: T) -> Result<&mut Self>137 pub fn name<T: AsRef<str>>(&mut self, name: T) -> Result<&mut Self> { 138 self.name = Some(util::str_to_cstring(name.as_ref())?); 139 self.opts.object_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr()); 140 Ok(self) 141 } 142 143 /// Set the pin_root_path for maps that are pinned by name. 144 /// 145 /// By default, this is NULL which bpf translates to /sys/fs/bpf pin_root_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self>146 pub fn pin_root_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self> { 147 self.pin_root_path = Some(util::path_to_cstring(path)?); 148 self.opts.pin_root_path = self 149 .pin_root_path 150 .as_ref() 151 .map_or(ptr::null(), |p| p.as_ptr()); 152 Ok(self) 153 } 154 155 /// Option to parse map definitions non-strictly, allowing extra attributes/data relaxed_maps(&mut self, relaxed_maps: bool) -> &mut Self156 pub fn relaxed_maps(&mut self, relaxed_maps: bool) -> &mut Self { 157 self.opts.relaxed_maps = relaxed_maps; 158 self 159 } 160 161 /// Option to print debug output to stderr. 162 /// 163 /// Note: This function uses [`set_print`] internally and will overwrite any callbacks 164 /// currently in use. debug(&mut self, dbg: bool) -> &mut Self165 pub fn debug(&mut self, dbg: bool) -> &mut Self { 166 if dbg { 167 set_print(Some((PrintLevel::Debug, |_, s| print!("{s}")))); 168 } else { 169 set_print(None); 170 } 171 self 172 } 173 174 /// Open an object using the provided path on the file system. open_file<P: AsRef<Path>>(&mut self, path: P) -> Result<OpenObject>175 pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> Result<OpenObject> { 176 let path = path.as_ref(); 177 let path_c = util::path_to_cstring(path)?; 178 let path_ptr = path_c.as_ptr(); 179 let opts_ptr = self.as_libbpf_object().as_ptr(); 180 181 let ptr = unsafe { libbpf_sys::bpf_object__open_file(path_ptr, opts_ptr) }; 182 let ptr = validate_bpf_ret(ptr) 183 .with_context(|| format!("failed to open object from `{}`", path.display()))?; 184 185 let obj = unsafe { OpenObject::from_ptr(ptr) }; 186 Ok(obj) 187 } 188 189 /// Open an object from memory. open_memory(&mut self, mem: &[u8]) -> Result<OpenObject>190 pub fn open_memory(&mut self, mem: &[u8]) -> Result<OpenObject> { 191 let opts_ptr = self.as_libbpf_object().as_ptr(); 192 let ptr = unsafe { 193 libbpf_sys::bpf_object__open_mem( 194 mem.as_ptr() as *const c_void, 195 mem.len() as libbpf_sys::size_t, 196 opts_ptr, 197 ) 198 }; 199 let ptr = validate_bpf_ret(ptr).context("failed to open object from memory")?; 200 let obj = unsafe { OpenObject::from_ptr(ptr) }; 201 Ok(obj) 202 } 203 } 204 205 impl AsRawLibbpf for ObjectBuilder { 206 type LibbpfType = libbpf_sys::bpf_object_open_opts; 207 208 /// Retrieve the underlying [`libbpf_sys::bpf_object_open_opts`]. as_libbpf_object(&self) -> NonNull<Self::LibbpfType>209 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> { 210 // SAFETY: A reference is always a valid pointer. 211 unsafe { NonNull::new_unchecked(addr_of!(self.opts).cast_mut()) } 212 } 213 } 214 215 216 /// Represents an opened (but not yet loaded) BPF object file. 217 /// 218 /// Use this object to access [`OpenMap`]s and [`OpenProgram`]s. 219 #[derive(Debug)] 220 #[repr(transparent)] 221 pub struct OpenObject { 222 ptr: NonNull<libbpf_sys::bpf_object>, 223 } 224 225 impl OpenObject { 226 /// Takes ownership from pointer. 227 /// 228 /// # Safety 229 /// 230 /// Operations on the returned object are undefined if `ptr` is any one of: 231 /// - null 232 /// - points to an unopened `bpf_object` 233 /// - points to a loaded `bpf_object` 234 /// 235 /// It is not safe to manipulate `ptr` after this operation. from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self236 pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self { 237 Self { ptr } 238 } 239 240 /// Takes underlying `libbpf_sys::bpf_object` pointer. take_ptr(mut self) -> NonNull<libbpf_sys::bpf_object>241 pub fn take_ptr(mut self) -> NonNull<libbpf_sys::bpf_object> { 242 let ptr = { 243 let Self { ptr } = &mut self; 244 *ptr 245 }; 246 // avoid double free of self.ptr 247 mem::forget(self); 248 ptr 249 } 250 251 /// Retrieve the object's name. name(&self) -> Option<&OsStr>252 pub fn name(&self) -> Option<&OsStr> { 253 // SAFETY: We ensured `ptr` is valid during construction. 254 let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) }; 255 // SAFETY: `libbpf_get_error` is always safe to call. 256 let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) }; 257 if err != 0 { 258 return None 259 } 260 let name_c_str = unsafe { CStr::from_ptr(name_ptr) }; 261 let str = OsStr::from_bytes(name_c_str.to_bytes()); 262 Some(str) 263 } 264 265 /// Retrieve an iterator over all BPF maps in the object. maps(&self) -> impl Iterator<Item = OpenMap<'_>>266 pub fn maps(&self) -> impl Iterator<Item = OpenMap<'_>> { 267 MapIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { OpenMap::new(ptr.as_ref()) }) 268 } 269 270 /// Retrieve an iterator over all BPF maps in the object. maps_mut(&mut self) -> impl Iterator<Item = OpenMapMut<'_>>271 pub fn maps_mut(&mut self) -> impl Iterator<Item = OpenMapMut<'_>> { 272 MapIter::new(unsafe { self.ptr.as_ref() }) 273 .map(|mut ptr| unsafe { OpenMapMut::new_mut(ptr.as_mut()) }) 274 } 275 276 /// Retrieve an iterator over all BPF programs in the object. progs(&self) -> impl Iterator<Item = OpenProgram<'_>>277 pub fn progs(&self) -> impl Iterator<Item = OpenProgram<'_>> { 278 ProgIter::new(unsafe { self.ptr.as_ref() }) 279 .map(|ptr| unsafe { OpenProgram::new(ptr.as_ref()) }) 280 } 281 282 /// Retrieve an iterator over all BPF programs in the object. progs_mut(&mut self) -> impl Iterator<Item = OpenProgramMut<'_>>283 pub fn progs_mut(&mut self) -> impl Iterator<Item = OpenProgramMut<'_>> { 284 ProgIter::new(unsafe { self.ptr.as_ref() }) 285 .map(|mut ptr| unsafe { OpenProgramMut::new_mut(ptr.as_mut()) }) 286 } 287 288 /// Load the maps and programs contained in this BPF object into the system. load(self) -> Result<Object>289 pub fn load(self) -> Result<Object> { 290 let ret = unsafe { libbpf_sys::bpf_object__load(self.ptr.as_ptr()) }; 291 let () = util::parse_ret(ret)?; 292 293 let obj = unsafe { Object::from_ptr(self.take_ptr()) }; 294 295 Ok(obj) 296 } 297 } 298 299 impl AsRawLibbpf for OpenObject { 300 type LibbpfType = libbpf_sys::bpf_object; 301 302 /// Retrieve the underlying [`libbpf_sys::bpf_object`]. as_libbpf_object(&self) -> NonNull<Self::LibbpfType>303 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> { 304 self.ptr 305 } 306 } 307 308 impl Drop for OpenObject { drop(&mut self)309 fn drop(&mut self) { 310 // `self.ptr` may be null if `load()` was called. This is ok: libbpf noops 311 unsafe { 312 libbpf_sys::bpf_object__close(self.ptr.as_ptr()); 313 } 314 } 315 } 316 317 /// Represents a loaded BPF object file. 318 /// 319 /// An `Object` is logically in charge of all the contained [`Program`]s and [`Map`]s as well as 320 /// the associated metadata and runtime state that underpins the userspace portions of BPF program 321 /// execution. As a libbpf-rs user, you must keep the `Object` alive during the entire lifetime 322 /// of your interaction with anything inside the `Object`. 323 /// 324 /// Note that this is an explanation of the motivation -- Rust's lifetime system should already be 325 /// enforcing this invariant. 326 #[derive(Debug)] 327 #[repr(transparent)] 328 pub struct Object { 329 ptr: NonNull<libbpf_sys::bpf_object>, 330 } 331 332 impl Object { 333 /// Takes ownership from pointer. 334 /// 335 /// # Safety 336 /// 337 /// If `ptr` is not already loaded then further operations on the returned object are 338 /// undefined. 339 /// 340 /// It is not safe to manipulate `ptr` after this operation. from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self341 pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self { 342 Self { ptr } 343 } 344 345 /// Retrieve the object's name. name(&self) -> Option<&OsStr>346 pub fn name(&self) -> Option<&OsStr> { 347 // SAFETY: We ensured `ptr` is valid during construction. 348 let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) }; 349 // SAFETY: `libbpf_get_error` is always safe to call. 350 let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) }; 351 if err != 0 { 352 return None 353 } 354 let name_c_str = unsafe { CStr::from_ptr(name_ptr) }; 355 let str = OsStr::from_bytes(name_c_str.to_bytes()); 356 Some(str) 357 } 358 359 /// Parse the btf information associated with this bpf object. btf(&self) -> Result<Option<Btf<'_>>>360 pub fn btf(&self) -> Result<Option<Btf<'_>>> { 361 Btf::from_bpf_object(unsafe { &*self.ptr.as_ptr() }) 362 } 363 364 /// Retrieve an iterator over all BPF maps in the object. maps(&self) -> impl Iterator<Item = Map<'_>>365 pub fn maps(&self) -> impl Iterator<Item = Map<'_>> { 366 MapIter::new(unsafe { self.ptr.as_ref() }) 367 .filter(|ptr| map_fd(*ptr).is_some()) 368 .map(|ptr| unsafe { Map::new(ptr.as_ref()) }) 369 } 370 371 /// Retrieve an iterator over all BPF maps in the object. maps_mut(&mut self) -> impl Iterator<Item = MapMut<'_>>372 pub fn maps_mut(&mut self) -> impl Iterator<Item = MapMut<'_>> { 373 MapIter::new(unsafe { self.ptr.as_ref() }) 374 .filter(|ptr| map_fd(*ptr).is_some()) 375 .map(|mut ptr| unsafe { MapMut::new_mut(ptr.as_mut()) }) 376 } 377 378 /// Retrieve an iterator over all BPF programs in the object. progs(&self) -> impl Iterator<Item = Program<'_>>379 pub fn progs(&self) -> impl Iterator<Item = Program<'_>> { 380 ProgIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { Program::new(ptr.as_ref()) }) 381 } 382 383 /// Retrieve an iterator over all BPF programs in the object. progs_mut(&self) -> impl Iterator<Item = ProgramMut<'_>>384 pub fn progs_mut(&self) -> impl Iterator<Item = ProgramMut<'_>> { 385 ProgIter::new(unsafe { self.ptr.as_ref() }) 386 .map(|mut ptr| unsafe { ProgramMut::new_mut(ptr.as_mut()) }) 387 } 388 } 389 390 impl AsRawLibbpf for Object { 391 type LibbpfType = libbpf_sys::bpf_object; 392 393 /// Retrieve the underlying [`libbpf_sys::bpf_object`]. as_libbpf_object(&self) -> NonNull<Self::LibbpfType>394 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> { 395 self.ptr 396 } 397 } 398 399 impl Drop for Object { drop(&mut self)400 fn drop(&mut self) { 401 unsafe { 402 libbpf_sys::bpf_object__close(self.ptr.as_ptr()); 403 } 404 } 405 } 406