1use 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 ($(#[$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 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 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#[derive(Clone, Debug)]
95pub struct LineInfo {
96 pub insn_off: u32,
98 pub file_name_off: u32,
100 pub line_off: u32,
102 pub line_num: u32,
104 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#[derive(Debug, Clone, Default)]
122#[repr(C)]
123pub struct Tag(pub [u8; 8]);
124
125#[derive(Debug, Clone)]
127pub struct ProgramInfo {
128 pub name: CString,
130 pub ty: ProgramType,
132 pub tag: Tag,
135 pub id: u32,
137 pub jited_prog_insns: Vec<u8>,
139 pub xlated_prog_insns: Vec<u8>,
141 pub load_time: Duration,
143 pub created_by_uid: u32,
145 pub map_ids: Vec<u32>,
147 pub ifindex: u32,
149 pub gpl_compatible: bool,
151 pub netns_dev: u64,
153 pub netns_ino: u64,
155 pub jited_ksyms: Vec<*const c_void>,
157 pub jited_func_lens: Vec<u32>,
159 pub btf_id: u32,
161 pub func_info_rec_size: u32,
163 pub func_info: Vec<libbpf_sys::bpf_func_info>,
165 pub line_info: Vec<LineInfo>,
167 pub jited_line_info: Vec<*const c_void>,
169 pub line_info_rec_size: u32,
171 pub jited_line_info_rec_size: u32,
173 pub prog_tags: Vec<Tag>,
175 pub run_time_ns: u64,
177 pub run_cnt: u64,
179 pub recursion_misses: u64,
181}
182
183#[derive(Default, Debug)]
185pub struct ProgInfoIter {
186 cur_id: u32,
187 opts: ProgInfoQueryOptions,
188}
189
190#[derive(Clone, Default, Debug)]
192pub struct ProgInfoQueryOptions {
193 include_xlated_prog_insns: bool,
195 include_jited_prog_insns: bool,
197 include_map_ids: bool,
199 include_line_info: bool,
201 include_func_info: bool,
203 include_jited_line_info: bool,
205 include_jited_func_lens: bool,
207 include_prog_tags: bool,
209 include_jited_ksyms: bool,
211}
212
213impl ProgInfoIter {
214 pub fn with_query_opts(opts: ProgInfoQueryOptions) -> Self {
216 Self {
217 opts,
218 ..Self::default()
219 }
220 }
221}
222
223impl ProgInfoQueryOptions {
224 pub fn include_xlated_prog_insns(mut self, v: bool) -> Self {
226 self.include_xlated_prog_insns = v;
227 self
228 }
229
230 pub fn include_jited_prog_insns(mut self, v: bool) -> Self {
232 self.include_jited_prog_insns = v;
233 self
234 }
235
236 pub fn include_map_ids(mut self, v: bool) -> Self {
238 self.include_map_ids = v;
239 self
240 }
241
242 pub fn include_line_info(mut self, v: bool) -> Self {
244 self.include_line_info = v;
245 self
246 }
247
248 pub fn include_func_info(mut self, v: bool) -> Self {
250 self.include_func_info = v;
251 self
252 }
253
254 pub fn include_jited_line_info(mut self, v: bool) -> Self {
256 self.include_jited_line_info = v;
257 self
258 }
259
260 pub fn include_jited_func_lens(mut self, v: bool) -> Self {
262 self.include_jited_func_lens = v;
263 self
264 }
265
266 pub fn include_prog_tags(mut self, v: bool) -> Self {
268 self.include_prog_tags = v;
269 self
270 }
271
272 pub fn include_jited_ksyms(mut self, v: bool) -> Self {
274 self.include_jited_ksyms = v;
275 self
276 }
277
278 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 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#[derive(Debug, Clone)]
458pub struct MapInfo {
459 pub name: CString,
461 pub ty: MapType,
463 pub id: u32,
465 pub key_size: u32,
467 pub value_size: u32,
469 pub max_entries: u32,
471 pub map_flags: u32,
473 pub ifindex: u32,
476 pub btf_vmlinux_value_type_id: u32,
478 pub netns_dev: u64,
480 pub netns_ino: u64,
482 pub btf_id: u32,
485 pub btf_key_type_id: u32,
487 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 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 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#[derive(Debug, Clone)]
527pub struct BtfInfo {
528 pub name: CString,
530 pub btf: Vec<u8>,
532 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 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 name: CString::from_vec_with_nul(name).unwrap(),
569 btf,
570 id: item.id,
571 })
572 }
573}
574
575#[derive(Debug, Default)]
576pub struct BtfInfoIter {
579 cur_id: u32,
580}
581
582impl BtfInfoIter {
583 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#[derive(Debug, Clone)]
616pub struct RawTracepointLinkInfo {
617 pub name: String,
619}
620
621#[derive(Debug, Clone)]
623pub struct TracingLinkInfo {
624 pub attach_type: ProgramAttachType,
626}
627
628#[derive(Debug, Clone)]
630pub struct CgroupLinkInfo {
631 pub cgroup_id: u64,
633 pub attach_type: ProgramAttachType,
635}
636
637#[derive(Debug, Clone)]
639pub struct NetNsLinkInfo {
640 pub ino: u32,
642 pub attach_type: ProgramAttachType,
644}
645
646#[derive(Debug, Clone)]
648pub struct NetfilterLinkInfo {
649 pub protocol_family: u32,
651 pub hooknum: u32,
653 pub priority: i32,
655 pub flags: u32,
657}
658
659#[derive(Debug, Clone)]
661pub struct XdpLinkInfo {
662 pub ifindex: u32,
664}
665
666#[derive(Debug, Clone)]
668pub struct SockMapLinkInfo {
669 pub map_id: u32,
671 pub attach_type: ProgramAttachType,
673}
674
675#[derive(Debug, Clone)]
677pub struct NetkitLinkInfo {
678 pub ifindex: u32,
680 pub attach_type: ProgramAttachType,
682}
683
684#[derive(Debug, Clone)]
686pub struct TcxLinkInfo {
687 pub ifindex: u32,
689 pub attach_type: ProgramAttachType,
691}
692
693#[derive(Debug, Clone)]
695pub struct StructOpsLinkInfo {
696 pub map_id: u32,
698}
699
700#[derive(Debug, Clone)]
702pub struct KprobeMultiLinkInfo {
703 pub count: u32,
705 pub flags: u32,
707 pub missed: u64,
709}
710
711#[derive(Debug, Clone)]
713pub struct UprobeMultiLinkInfo {
714 pub path_size: u32,
716 pub count: u32,
718 pub flags: u32,
720 pub pid: u32,
722}
723
724#[derive(Debug, Clone)]
727pub enum LinkTypeInfo {
728 RawTracepoint(RawTracepointLinkInfo),
732 Tracing(TracingLinkInfo),
734 Cgroup(CgroupLinkInfo),
738 Iter,
740 NetNs(NetNsLinkInfo),
742 Xdp(XdpLinkInfo),
747 StructOps(StructOpsLinkInfo),
752 Netfilter(NetfilterLinkInfo),
754 KprobeMulti(KprobeMultiLinkInfo),
756 UprobeMulti(UprobeMultiLinkInfo),
758 Tcx(TcxLinkInfo),
760 Netkit(NetkitLinkInfo),
762 SockMap(SockMapLinkInfo),
764 PerfEvent,
766 Unknown,
768}
769
770#[derive(Debug, Clone)]
772pub struct LinkInfo {
773 pub info: LinkTypeInfo,
775 pub id: u32,
777 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 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);