libbpf_rs/
query.rs

1//! Query the host about BPF
2//!
3//! For example, to list the name of every bpf program running on the system:
4//! ```
5//! use libbpf_rs::query::ProgInfoIter;
6//!
7//! let mut iter = ProgInfoIter::default();
8//! for prog in iter {
9//!     println!("{}", prog.name.to_string_lossy());
10//! }
11//! ```
12
13use std::ffi::c_void;
14use std::ffi::CString;
15use std::io;
16use std::mem::size_of_val;
17use std::os::fd::AsFd;
18use std::os::fd::AsRawFd;
19use std::os::fd::BorrowedFd;
20use std::os::fd::FromRawFd;
21use std::os::fd::OwnedFd;
22use std::os::raw::c_char;
23use std::ptr;
24use std::time::Duration;
25
26use crate::util;
27use crate::MapType;
28use crate::ProgramAttachType;
29use crate::ProgramType;
30use crate::Result;
31
32macro_rules! gen_info_impl {
33    // This magic here allows us to embed doc comments into macro expansions
34    ($(#[$attr:meta])*
35     $name:ident, $info_ty:ty, $uapi_info_ty:ty, $next_id:expr, $fd_by_id:expr) => {
36        $(#[$attr])*
37        #[derive(Default, Debug)]
38        pub struct $name {
39            cur_id: u32,
40        }
41
42        impl $name {
43            // Returns Some(next_valid_fd), None on none left
44            fn next_valid_fd(&mut self) -> Option<OwnedFd> {
45                loop {
46                    if unsafe { $next_id(self.cur_id, &mut self.cur_id) } != 0 {
47                        return None;
48                    }
49
50                    let fd = unsafe { $fd_by_id(self.cur_id) };
51                    if fd < 0 {
52                        let err = io::Error::last_os_error();
53                        if err.kind() == io::ErrorKind::NotFound {
54                            continue;
55                        }
56
57                        return None;
58                    }
59
60                    return Some(unsafe { OwnedFd::from_raw_fd(fd)});
61                }
62            }
63        }
64
65        impl Iterator for $name {
66            type Item = $info_ty;
67
68            fn next(&mut self) -> Option<Self::Item> {
69                let fd = self.next_valid_fd()?;
70
71                // We need to use std::mem::zeroed() instead of just using
72                // ::default() because padding bytes need to be zero as well.
73                // Old kernels which know about fewer fields than we do will
74                // check to make sure every byte past what they know is zero
75                // and will return E2BIG otherwise.
76                let mut item: $uapi_info_ty = unsafe { std::mem::zeroed() };
77                let item_ptr: *mut $uapi_info_ty = &mut item;
78                let mut len = size_of_val(&item) as u32;
79
80                let ret = unsafe { libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len) };
81                let parsed_uapi = if ret != 0 {
82                    None
83                } else {
84                    <$info_ty>::from_uapi(fd.as_fd(), item)
85                };
86
87                parsed_uapi
88            }
89        }
90    };
91}
92
93/// BTF Line information.
94#[derive(Clone, Debug)]
95pub struct LineInfo {
96    /// Offset of instruction in vector.
97    pub insn_off: u32,
98    /// File name offset.
99    pub file_name_off: u32,
100    /// Line offset in debug info.
101    pub line_off: u32,
102    /// Line number.
103    pub line_num: u32,
104    /// Line column number.
105    pub line_col: u32,
106}
107
108impl From<&libbpf_sys::bpf_line_info> for LineInfo {
109    fn from(item: &libbpf_sys::bpf_line_info) -> Self {
110        LineInfo {
111            insn_off: item.insn_off,
112            file_name_off: item.file_name_off,
113            line_off: item.line_off,
114            line_num: item.line_col >> 10,
115            line_col: item.line_col & 0x3ff,
116        }
117    }
118}
119
120/// Bpf identifier tag.
121#[derive(Debug, Clone, Default)]
122#[repr(C)]
123pub struct Tag(pub [u8; 8]);
124
125/// Information about a BPF program. Maps to `struct bpf_prog_info` in kernel uapi.
126#[derive(Debug, Clone)]
127pub struct ProgramInfo {
128    /// A user-defined name for the BPF program (null-terminated string).
129    pub name: CString,
130    /// The type of the program.
131    pub ty: ProgramType,
132    /// An 8-byte hash (`BPF_TAG_SIZE`) computed from the program's
133    /// contents; used to detect changes in the program code.
134    pub tag: Tag,
135    /// A unique identifier for the program instance.
136    pub id: u32,
137    /// JIT-compiled instructions.
138    pub jited_prog_insns: Vec<u8>,
139    /// Translated BPF instructions in an intermediate representation.
140    pub xlated_prog_insns: Vec<u8>,
141    /// Time (since system boot) at which the program was loaded.
142    pub load_time: Duration,
143    /// UID of the user who loaded the program.
144    pub created_by_uid: u32,
145    /// Array of map IDs associated with this program.
146    pub map_ids: Vec<u32>,
147    /// Network interface index if the program is attached to a specific device.
148    pub ifindex: u32,
149    /// Whether the program is GPL compatible.
150    pub gpl_compatible: bool,
151    /// Device ID of the network namespace that the program is associated with.
152    pub netns_dev: u64,
153    /// Inode number of the network namespace associated with the program.
154    pub netns_ino: u64,
155    /// Number of kernel symbols in the JITed code (if available).
156    pub jited_ksyms: Vec<*const c_void>,
157    /// Number of function length records available for the JITed code.
158    pub jited_func_lens: Vec<u32>,
159    /// Identifier of the associated BTF (BPF Type Format) data.
160    pub btf_id: u32,
161    /// Size (in bytes) of each record in the function info array.
162    pub func_info_rec_size: u32,
163    /// Array of function info records for this program.
164    pub func_info: Vec<libbpf_sys::bpf_func_info>,
165    /// Array of line info records mapping BPF instructions to source code lines.
166    pub line_info: Vec<LineInfo>,
167    /// Line info records for the JIT-compiled code.
168    pub jited_line_info: Vec<*const c_void>,
169    /// Size (in bytes) of each line info record.
170    pub line_info_rec_size: u32,
171    /// Size (in bytes) of each record in the JITed line info array.
172    pub jited_line_info_rec_size: u32,
173    /// Array of program tags.
174    pub prog_tags: Vec<Tag>,
175    /// Total accumulated run time (in nanoseconds) for the program's execution.
176    pub run_time_ns: u64,
177    /// Total number of times the program has been executed.
178    pub run_cnt: u64,
179    /// Skipped BPF executions due to recursion or concurrent execution prevention.
180    pub recursion_misses: u64,
181}
182
183/// An iterator for the information of loaded bpf programs.
184#[derive(Default, Debug)]
185pub struct ProgInfoIter {
186    cur_id: u32,
187    opts: ProgInfoQueryOptions,
188}
189
190/// Options to query the program info currently loaded.
191#[derive(Clone, Default, Debug)]
192pub struct ProgInfoQueryOptions {
193    /// Include the vector of bpf instructions in the result.
194    include_xlated_prog_insns: bool,
195    /// Include the vector of jited instructions in the result.
196    include_jited_prog_insns: bool,
197    /// Include the ids of maps associated with the program.
198    include_map_ids: bool,
199    /// Include source line information corresponding to xlated code.
200    include_line_info: bool,
201    /// Include function type information corresponding to xlated code.
202    include_func_info: bool,
203    /// Include source line information corresponding to jited code.
204    include_jited_line_info: bool,
205    /// Include function type information corresponding to jited code.
206    include_jited_func_lens: bool,
207    /// Include program tags.
208    include_prog_tags: bool,
209    /// Include the jited kernel symbols.
210    include_jited_ksyms: bool,
211}
212
213impl ProgInfoIter {
214    /// Generate an iter from more specific query options.
215    pub fn with_query_opts(opts: ProgInfoQueryOptions) -> Self {
216        Self {
217            opts,
218            ..Self::default()
219        }
220    }
221}
222
223impl ProgInfoQueryOptions {
224    /// Include the vector of jited bpf instructions in the result.
225    pub fn include_xlated_prog_insns(mut self, v: bool) -> Self {
226        self.include_xlated_prog_insns = v;
227        self
228    }
229
230    /// Include the vector of jited instructions in the result.
231    pub fn include_jited_prog_insns(mut self, v: bool) -> Self {
232        self.include_jited_prog_insns = v;
233        self
234    }
235
236    /// Include the ids of maps associated with the program.
237    pub fn include_map_ids(mut self, v: bool) -> Self {
238        self.include_map_ids = v;
239        self
240    }
241
242    /// Include source line information corresponding to xlated code.
243    pub fn include_line_info(mut self, v: bool) -> Self {
244        self.include_line_info = v;
245        self
246    }
247
248    /// Include function type information corresponding to xlated code.
249    pub fn include_func_info(mut self, v: bool) -> Self {
250        self.include_func_info = v;
251        self
252    }
253
254    /// Include source line information corresponding to jited code.
255    pub fn include_jited_line_info(mut self, v: bool) -> Self {
256        self.include_jited_line_info = v;
257        self
258    }
259
260    /// Include function type information corresponding to jited code.
261    pub fn include_jited_func_lens(mut self, v: bool) -> Self {
262        self.include_jited_func_lens = v;
263        self
264    }
265
266    /// Include program tags.
267    pub fn include_prog_tags(mut self, v: bool) -> Self {
268        self.include_prog_tags = v;
269        self
270    }
271
272    /// Include the jited kernel symbols.
273    pub fn include_jited_ksyms(mut self, v: bool) -> Self {
274        self.include_jited_ksyms = v;
275        self
276    }
277
278    /// Include everything there is in the query results.
279    pub fn include_all(self) -> Self {
280        Self {
281            include_xlated_prog_insns: true,
282            include_jited_prog_insns: true,
283            include_map_ids: true,
284            include_line_info: true,
285            include_func_info: true,
286            include_jited_line_info: true,
287            include_jited_func_lens: true,
288            include_prog_tags: true,
289            include_jited_ksyms: true,
290        }
291    }
292}
293
294impl ProgramInfo {
295    fn load_from_fd(fd: BorrowedFd<'_>, opts: &ProgInfoQueryOptions) -> Result<Self> {
296        let mut item = libbpf_sys::bpf_prog_info::default();
297
298        let mut xlated_prog_insns: Vec<u8> = Vec::new();
299        let mut jited_prog_insns: Vec<u8> = Vec::new();
300        let mut map_ids: Vec<u32> = Vec::new();
301        let mut jited_line_info: Vec<*const c_void> = Vec::new();
302        let mut line_info: Vec<libbpf_sys::bpf_line_info> = Vec::new();
303        let mut func_info: Vec<libbpf_sys::bpf_func_info> = Vec::new();
304        let mut jited_func_lens: Vec<u32> = Vec::new();
305        let mut prog_tags: Vec<Tag> = Vec::new();
306        let mut jited_ksyms: Vec<*const c_void> = Vec::new();
307
308        let item_ptr: *mut libbpf_sys::bpf_prog_info = &mut item;
309        let mut len = size_of_val(&item) as u32;
310
311        let ret = unsafe {
312            libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len)
313        };
314        util::parse_ret(ret)?;
315
316        // SANITY: `libbpf` should guarantee NUL termination.
317        let name = util::c_char_slice_to_cstr(&item.name).unwrap();
318        let ty = ProgramType::from(item.type_);
319
320        if opts.include_xlated_prog_insns {
321            xlated_prog_insns.resize(item.xlated_prog_len as usize, 0u8);
322            item.xlated_prog_insns = xlated_prog_insns.as_mut_ptr() as *mut c_void as u64;
323        } else {
324            item.xlated_prog_len = 0;
325        }
326
327        if opts.include_jited_prog_insns {
328            jited_prog_insns.resize(item.jited_prog_len as usize, 0u8);
329            item.jited_prog_insns = jited_prog_insns.as_mut_ptr() as *mut c_void as u64;
330        } else {
331            item.jited_prog_len = 0;
332        }
333
334        if opts.include_map_ids {
335            map_ids.resize(item.nr_map_ids as usize, 0u32);
336            item.map_ids = map_ids.as_mut_ptr() as *mut c_void as u64;
337        } else {
338            item.nr_map_ids = 0;
339        }
340
341        if opts.include_line_info {
342            line_info.resize(
343                item.nr_line_info as usize,
344                libbpf_sys::bpf_line_info::default(),
345            );
346            item.line_info = line_info.as_mut_ptr() as *mut c_void as u64;
347        } else {
348            item.nr_line_info = 0;
349        }
350
351        if opts.include_func_info {
352            func_info.resize(
353                item.nr_func_info as usize,
354                libbpf_sys::bpf_func_info::default(),
355            );
356            item.func_info = func_info.as_mut_ptr() as *mut c_void as u64;
357        } else {
358            item.nr_func_info = 0;
359        }
360
361        if opts.include_jited_line_info {
362            jited_line_info.resize(item.nr_jited_line_info as usize, ptr::null());
363            item.jited_line_info = jited_line_info.as_mut_ptr() as *mut c_void as u64;
364        } else {
365            item.nr_jited_line_info = 0;
366        }
367
368        if opts.include_jited_func_lens {
369            jited_func_lens.resize(item.nr_jited_func_lens as usize, 0);
370            item.jited_func_lens = jited_func_lens.as_mut_ptr() as *mut c_void as u64;
371        } else {
372            item.nr_jited_func_lens = 0;
373        }
374
375        if opts.include_prog_tags {
376            prog_tags.resize(item.nr_prog_tags as usize, Tag::default());
377            item.prog_tags = prog_tags.as_mut_ptr() as *mut c_void as u64;
378        } else {
379            item.nr_prog_tags = 0;
380        }
381
382        if opts.include_jited_ksyms {
383            jited_ksyms.resize(item.nr_jited_ksyms as usize, ptr::null());
384            item.jited_ksyms = jited_ksyms.as_mut_ptr() as *mut c_void as u64;
385        } else {
386            item.nr_jited_ksyms = 0;
387        }
388
389        let ret = unsafe {
390            libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len)
391        };
392        util::parse_ret(ret)?;
393
394        Ok(ProgramInfo {
395            name: name.to_owned(),
396            ty,
397            tag: Tag(item.tag),
398            id: item.id,
399            jited_prog_insns,
400            xlated_prog_insns,
401            load_time: Duration::from_nanos(item.load_time),
402            created_by_uid: item.created_by_uid,
403            map_ids,
404            ifindex: item.ifindex,
405            gpl_compatible: item._bitfield_1.get_bit(0),
406            netns_dev: item.netns_dev,
407            netns_ino: item.netns_ino,
408            jited_ksyms,
409            jited_func_lens,
410            btf_id: item.btf_id,
411            func_info_rec_size: item.func_info_rec_size,
412            func_info,
413            line_info: line_info.iter().map(Into::into).collect(),
414            jited_line_info,
415            line_info_rec_size: item.line_info_rec_size,
416            jited_line_info_rec_size: item.jited_line_info_rec_size,
417            prog_tags,
418            run_time_ns: item.run_time_ns,
419            run_cnt: item.run_cnt,
420            recursion_misses: item.recursion_misses,
421        })
422    }
423}
424
425impl ProgInfoIter {
426    fn next_valid_fd(&mut self) -> Option<OwnedFd> {
427        loop {
428            if unsafe { libbpf_sys::bpf_prog_get_next_id(self.cur_id, &mut self.cur_id) } != 0 {
429                return None;
430            }
431
432            let fd = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(self.cur_id) };
433            if fd < 0 {
434                let err = io::Error::last_os_error();
435                if err.kind() == io::ErrorKind::NotFound {
436                    continue;
437                }
438                return None;
439            }
440
441            return Some(unsafe { OwnedFd::from_raw_fd(fd) });
442        }
443    }
444}
445
446impl Iterator for ProgInfoIter {
447    type Item = ProgramInfo;
448
449    fn next(&mut self) -> Option<Self::Item> {
450        let fd = self.next_valid_fd()?;
451        let prog = ProgramInfo::load_from_fd(fd.as_fd(), &self.opts);
452        prog.ok()
453    }
454}
455
456/// Information about a BPF map. Maps to `struct bpf_map_info` in kernel uapi.
457#[derive(Debug, Clone)]
458pub struct MapInfo {
459    /// A user-defined name for the BPF Map (null-terminated string).
460    pub name: CString,
461    /// The BPF map type.
462    pub ty: MapType,
463    /// A unique identifier for this map instance.
464    pub id: u32,
465    /// Size (in bytes) of the keys stored in the map.
466    pub key_size: u32,
467    /// Size (in bytes) of the values stored in the map.
468    pub value_size: u32,
469    /// Maximum number of entries that the map can hold.
470    pub max_entries: u32,
471    /// Map flags indicating specific properties (e.g., `BPF_F_NO_PREALLOC`).
472    pub map_flags: u32,
473    /// Network interface index if the map is associated with a specific device. Otherwise, this
474    /// may be zero.
475    pub ifindex: u32,
476    /// BTF (BPF Type Format) type ID for the value type as defined in the vmlinux BTF data.
477    pub btf_vmlinux_value_type_id: u32,
478    /// Device identifier of the network namespace.
479    pub netns_dev: u64,
480    /// Inode number of the network namespace.
481    pub netns_ino: u64,
482    /// BTF ID referencing the BTF data for this map. This helps to verify the correctness of the
483    /// map's data structure as per BTF metadata.
484    pub btf_id: u32,
485    /// BTF type ID for the key type.
486    pub btf_key_type_id: u32,
487    /// BTF type ID for the value type.
488    pub btf_value_type_id: u32,
489}
490
491impl MapInfo {
492    fn from_uapi(_fd: BorrowedFd<'_>, s: libbpf_sys::bpf_map_info) -> Option<Self> {
493        // SANITY: `libbpf` should guarantee NUL termination.
494        let name = util::c_char_slice_to_cstr(&s.name).unwrap();
495        let ty = MapType::from(s.type_);
496
497        Some(Self {
498            name: name.to_owned(),
499            ty,
500            id: s.id,
501            key_size: s.key_size,
502            value_size: s.value_size,
503            max_entries: s.max_entries,
504            map_flags: s.map_flags,
505            ifindex: s.ifindex,
506            btf_vmlinux_value_type_id: s.btf_vmlinux_value_type_id,
507            netns_dev: s.netns_dev,
508            netns_ino: s.netns_ino,
509            btf_id: s.btf_id,
510            btf_key_type_id: s.btf_key_type_id,
511            btf_value_type_id: s.btf_value_type_id,
512        })
513    }
514}
515
516gen_info_impl!(
517    /// Iterator that returns [`MapInfo`]s.
518    MapInfoIter,
519    MapInfo,
520    libbpf_sys::bpf_map_info,
521    libbpf_sys::bpf_map_get_next_id,
522    libbpf_sys::bpf_map_get_fd_by_id
523);
524
525/// Information about BPF type format.
526#[derive(Debug, Clone)]
527pub struct BtfInfo {
528    /// The name associated with this btf information in the kernel.
529    pub name: CString,
530    /// The raw btf bytes from the kernel.
531    pub btf: Vec<u8>,
532    /// The btf id associated with this btf information in the kernel.
533    pub id: u32,
534}
535
536impl BtfInfo {
537    fn load_from_fd(fd: BorrowedFd<'_>) -> Result<Self> {
538        let mut item = libbpf_sys::bpf_btf_info::default();
539        let mut btf: Vec<u8> = Vec::new();
540        let mut name: Vec<u8> = Vec::new();
541
542        let item_ptr: *mut libbpf_sys::bpf_btf_info = &mut item;
543        let mut len = size_of_val(&item) as u32;
544
545        let ret = unsafe {
546            libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len)
547        };
548        util::parse_ret(ret)?;
549
550        // The API gives you the ascii string length while expecting
551        // you to give it back space for a nul-terminator
552        item.name_len += 1;
553        name.resize(item.name_len as usize, 0u8);
554        item.name = name.as_mut_ptr() as *mut c_void as u64;
555
556        btf.resize(item.btf_size as usize, 0u8);
557        item.btf = btf.as_mut_ptr() as *mut c_void as u64;
558
559        let ret = unsafe {
560            libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len)
561        };
562        util::parse_ret(ret)?;
563
564        Ok(BtfInfo {
565            // SANITY: Our buffer contained space for a NUL byte and we set its
566            //         contents to 0. Barring a `libbpf` bug a NUL byte will be
567            //         present.
568            name: CString::from_vec_with_nul(name).unwrap(),
569            btf,
570            id: item.id,
571        })
572    }
573}
574
575#[derive(Debug, Default)]
576/// An iterator for the btf type information of modules and programs
577/// in the kernel
578pub struct BtfInfoIter {
579    cur_id: u32,
580}
581
582impl BtfInfoIter {
583    // Returns Some(next_valid_fd), None on none left
584    fn next_valid_fd(&mut self) -> Option<OwnedFd> {
585        loop {
586            if unsafe { libbpf_sys::bpf_btf_get_next_id(self.cur_id, &mut self.cur_id) } != 0 {
587                return None;
588            }
589
590            let fd = unsafe { libbpf_sys::bpf_btf_get_fd_by_id(self.cur_id) };
591            if fd < 0 {
592                let err = io::Error::last_os_error();
593                if err.kind() == io::ErrorKind::NotFound {
594                    continue;
595                }
596                return None;
597            }
598
599            return Some(unsafe { OwnedFd::from_raw_fd(fd) });
600        }
601    }
602}
603
604impl Iterator for BtfInfoIter {
605    type Item = BtfInfo;
606
607    fn next(&mut self) -> Option<Self::Item> {
608        let fd = self.next_valid_fd()?;
609        let info = BtfInfo::load_from_fd(fd.as_fd());
610        info.ok()
611    }
612}
613
614/// Information about a raw tracepoint.
615#[derive(Debug, Clone)]
616pub struct RawTracepointLinkInfo {
617    /// The name of the raw tracepoint.
618    pub name: String,
619}
620
621/// Information about a tracing link
622#[derive(Debug, Clone)]
623pub struct TracingLinkInfo {
624    /// Attach type of the tracing link.
625    pub attach_type: ProgramAttachType,
626}
627
628/// Information about a cgroup link
629#[derive(Debug, Clone)]
630pub struct CgroupLinkInfo {
631    /// Identifier of the target cgroup.
632    pub cgroup_id: u64,
633    /// Attachment type for cgroup-based programs.
634    pub attach_type: ProgramAttachType,
635}
636
637/// Information about a network namespace link.
638#[derive(Debug, Clone)]
639pub struct NetNsLinkInfo {
640    /// Inode number of the network namespace.
641    pub ino: u32,
642    /// Attachment type for network namespace programs.
643    pub attach_type: ProgramAttachType,
644}
645
646/// Information about a BPF netfilter link.
647#[derive(Debug, Clone)]
648pub struct NetfilterLinkInfo {
649    /// Protocol family of the netfilter hook.
650    pub protocol_family: u32,
651    /// Netfilter hook number.
652    pub hooknum: u32,
653    /// Priority of the netfilter link.
654    pub priority: i32,
655    /// Flags used for the netfilter link.
656    pub flags: u32,
657}
658
659/// Information about a XDP link.
660#[derive(Debug, Clone)]
661pub struct XdpLinkInfo {
662    /// Interface index to which the XDP link is attached.
663    pub ifindex: u32,
664}
665
666/// Information about a BPF sockmap link.
667#[derive(Debug, Clone)]
668pub struct SockMapLinkInfo {
669    /// The ID of the BPF sockmap.
670    pub map_id: u32,
671    /// The type of program attached to the sockmap.
672    pub attach_type: ProgramAttachType,
673}
674
675/// Information about a BPF netkit link.
676#[derive(Debug, Clone)]
677pub struct NetkitLinkInfo {
678    /// Interface index to which the netkit link is attached.
679    pub ifindex: u32,
680    /// Type of program attached to the netkit link.
681    pub attach_type: ProgramAttachType,
682}
683
684/// Information about a BPF tc link.
685#[derive(Debug, Clone)]
686pub struct TcxLinkInfo {
687    /// Interface index to which the tc link is attached.
688    pub ifindex: u32,
689    /// Type of program attached to the tc link.
690    pub attach_type: ProgramAttachType,
691}
692
693/// Information about a BPF `struct_ops` link.
694#[derive(Debug, Clone)]
695pub struct StructOpsLinkInfo {
696    /// The ID of the BPF map to which the `struct_ops` link is attached.
697    pub map_id: u32,
698}
699
700/// Information about a multi-kprobe link.
701#[derive(Debug, Clone)]
702pub struct KprobeMultiLinkInfo {
703    /// Count of kprobe targets.
704    pub count: u32,
705    /// Flags for the link.
706    pub flags: u32,
707    /// Missed probes count.
708    pub missed: u64,
709}
710
711/// Information about a multi-uprobe link.
712#[derive(Debug, Clone)]
713pub struct UprobeMultiLinkInfo {
714    /// Size of the path.
715    pub path_size: u32,
716    /// Count of uprobe targets.
717    pub count: u32,
718    /// Flags for the link.
719    pub flags: u32,
720    /// PID to which the uprobe is attached.
721    pub pid: u32,
722}
723
724/// Information about BPF link types. Maps to the anonymous union in `struct bpf_link_info` in
725/// kernel uapi.
726#[derive(Debug, Clone)]
727pub enum LinkTypeInfo {
728    /// Link type for raw tracepoints.
729    ///
730    /// Contains information about the BPF program directly to a raw tracepoint.
731    RawTracepoint(RawTracepointLinkInfo),
732    /// Tracing link type.
733    Tracing(TracingLinkInfo),
734    /// Link type for cgroup programs.
735    ///
736    /// Contains information about the cgroups and its attachment type.
737    Cgroup(CgroupLinkInfo),
738    /// Iterator link type.
739    Iter,
740    /// Network namespace link type.
741    NetNs(NetNsLinkInfo),
742    /// Link type for XDP programs.
743    ///
744    /// Contains information about the XDP link, such as the interface index
745    /// to which the XDP link is attached.
746    Xdp(XdpLinkInfo),
747    /// Link type for `struct_ops` programs.
748    ///
749    /// Contains information about the BPF map to which the `struct_ops` link is
750    /// attached.
751    StructOps(StructOpsLinkInfo),
752    /// Link type for netfilter programs.
753    Netfilter(NetfilterLinkInfo),
754    /// Link type for kprobe-multi links.
755    KprobeMulti(KprobeMultiLinkInfo),
756    /// Link type for multi-uprobe links.
757    UprobeMulti(UprobeMultiLinkInfo),
758    /// Link type for TC programs.
759    Tcx(TcxLinkInfo),
760    /// Link type for netkit programs.
761    Netkit(NetkitLinkInfo),
762    /// Link type for sockmap programs.
763    SockMap(SockMapLinkInfo),
764    /// Link type for perf-event programs.
765    PerfEvent,
766    /// Unknown link type.
767    Unknown,
768}
769
770/// Information about a BPF link. Maps to `struct bpf_link_info` in kernel uapi.
771#[derive(Debug, Clone)]
772pub struct LinkInfo {
773    /// Information about the BPF link type.
774    pub info: LinkTypeInfo,
775    /// Unique identifier of the BPF link.
776    pub id: u32,
777    /// ID of the BPF program attached via this link.
778    pub prog_id: u32,
779}
780
781impl LinkInfo {
782    fn from_uapi(fd: BorrowedFd<'_>, mut s: libbpf_sys::bpf_link_info) -> Option<Self> {
783        let type_info = match s.type_ {
784            libbpf_sys::BPF_LINK_TYPE_RAW_TRACEPOINT => {
785                let mut buf = [0; 256];
786                s.__bindgen_anon_1.raw_tracepoint.tp_name = buf.as_mut_ptr() as u64;
787                s.__bindgen_anon_1.raw_tracepoint.tp_name_len = buf.len() as u32;
788                let item_ptr: *mut libbpf_sys::bpf_link_info = &mut s;
789                let mut len = size_of_val(&s) as u32;
790
791                let ret = unsafe {
792                    libbpf_sys::bpf_obj_get_info_by_fd(
793                        fd.as_raw_fd(),
794                        item_ptr as *mut c_void,
795                        &mut len,
796                    )
797                };
798                if ret != 0 {
799                    return None;
800                }
801
802                LinkTypeInfo::RawTracepoint(RawTracepointLinkInfo {
803                    name: util::c_ptr_to_string(
804                        unsafe { s.__bindgen_anon_1.raw_tracepoint.tp_name } as *const c_char,
805                    )
806                    .unwrap_or_else(|_| "?".to_string()),
807                })
808            }
809            libbpf_sys::BPF_LINK_TYPE_TRACING => LinkTypeInfo::Tracing(TracingLinkInfo {
810                attach_type: ProgramAttachType::from(unsafe {
811                    s.__bindgen_anon_1.tracing.attach_type
812                }),
813            }),
814            libbpf_sys::BPF_LINK_TYPE_CGROUP => LinkTypeInfo::Cgroup(CgroupLinkInfo {
815                cgroup_id: unsafe { s.__bindgen_anon_1.cgroup.cgroup_id },
816                attach_type: ProgramAttachType::from(unsafe {
817                    s.__bindgen_anon_1.cgroup.attach_type
818                }),
819            }),
820            libbpf_sys::BPF_LINK_TYPE_ITER => LinkTypeInfo::Iter,
821            libbpf_sys::BPF_LINK_TYPE_NETNS => LinkTypeInfo::NetNs(NetNsLinkInfo {
822                ino: unsafe { s.__bindgen_anon_1.netns.netns_ino },
823                attach_type: ProgramAttachType::from(unsafe {
824                    s.__bindgen_anon_1.netns.attach_type
825                }),
826            }),
827            libbpf_sys::BPF_LINK_TYPE_NETFILTER => LinkTypeInfo::Netfilter(NetfilterLinkInfo {
828                protocol_family: unsafe { s.__bindgen_anon_1.netfilter.pf },
829                hooknum: unsafe { s.__bindgen_anon_1.netfilter.hooknum },
830                priority: unsafe { s.__bindgen_anon_1.netfilter.priority },
831                flags: unsafe { s.__bindgen_anon_1.netfilter.flags },
832            }),
833            libbpf_sys::BPF_LINK_TYPE_XDP => LinkTypeInfo::Xdp(XdpLinkInfo {
834                ifindex: unsafe { s.__bindgen_anon_1.xdp.ifindex },
835            }),
836            libbpf_sys::BPF_LINK_TYPE_NETKIT => LinkTypeInfo::Netkit(NetkitLinkInfo {
837                ifindex: unsafe { s.__bindgen_anon_1.netkit.ifindex },
838                attach_type: ProgramAttachType::from(unsafe {
839                    s.__bindgen_anon_1.netkit.attach_type
840                }),
841            }),
842            libbpf_sys::BPF_LINK_TYPE_TCX => LinkTypeInfo::Tcx(TcxLinkInfo {
843                ifindex: unsafe { s.__bindgen_anon_1.tcx.ifindex },
844                attach_type: ProgramAttachType::from(unsafe { s.__bindgen_anon_1.tcx.attach_type }),
845            }),
846            libbpf_sys::BPF_LINK_TYPE_STRUCT_OPS => LinkTypeInfo::StructOps(StructOpsLinkInfo {
847                map_id: unsafe { s.__bindgen_anon_1.struct_ops.map_id },
848            }),
849            libbpf_sys::BPF_LINK_TYPE_KPROBE_MULTI => {
850                LinkTypeInfo::KprobeMulti(KprobeMultiLinkInfo {
851                    count: unsafe { s.__bindgen_anon_1.kprobe_multi.count },
852                    flags: unsafe { s.__bindgen_anon_1.kprobe_multi.flags },
853                    missed: unsafe { s.__bindgen_anon_1.kprobe_multi.missed },
854                })
855            }
856            libbpf_sys::BPF_LINK_TYPE_UPROBE_MULTI => {
857                LinkTypeInfo::UprobeMulti(UprobeMultiLinkInfo {
858                    path_size: unsafe { s.__bindgen_anon_1.uprobe_multi.path_size },
859                    count: unsafe { s.__bindgen_anon_1.uprobe_multi.count },
860                    flags: unsafe { s.__bindgen_anon_1.uprobe_multi.flags },
861                    pid: unsafe { s.__bindgen_anon_1.uprobe_multi.pid },
862                })
863            }
864            libbpf_sys::BPF_LINK_TYPE_SOCKMAP => LinkTypeInfo::SockMap(SockMapLinkInfo {
865                map_id: unsafe { s.__bindgen_anon_1.sockmap.map_id },
866                attach_type: ProgramAttachType::from(unsafe {
867                    s.__bindgen_anon_1.sockmap.attach_type
868                }),
869            }),
870            libbpf_sys::BPF_LINK_TYPE_PERF_EVENT => LinkTypeInfo::PerfEvent,
871            _ => LinkTypeInfo::Unknown,
872        };
873
874        Some(Self {
875            info: type_info,
876            id: s.id,
877            prog_id: s.prog_id,
878        })
879    }
880}
881
882gen_info_impl!(
883    /// Iterator that returns [`LinkInfo`]s.
884    LinkInfoIter,
885    LinkInfo,
886    libbpf_sys::bpf_link_info,
887    libbpf_sys::bpf_link_get_next_id,
888    libbpf_sys::bpf_link_get_fd_by_id
889);