1mod info;
41mod probe;
42mod utils;
43
44pub mod cgroup_device;
46pub mod cgroup_skb;
47pub mod cgroup_sock;
48pub mod cgroup_sock_addr;
49pub mod cgroup_sockopt;
50pub mod cgroup_sysctl;
51pub mod extension;
52pub mod fentry;
53pub mod fexit;
54pub mod flow_dissector;
55pub mod iter;
56pub mod kprobe;
57pub mod links;
58pub mod lirc_mode2;
59pub mod lsm;
60pub mod lsm_cgroup;
61pub mod perf_attach;
62pub mod perf_event;
63pub mod raw_trace_point;
64pub mod sk_lookup;
65pub mod sk_msg;
66pub mod sk_skb;
67pub mod sock_ops;
68pub mod socket_filter;
69pub mod tc;
70pub mod tp_btf;
71pub mod trace_point;
72pub mod uprobe;
73pub mod xdp;
74
75use std::{
76 borrow::Cow,
77 ffi::CString,
78 io,
79 os::fd::{AsFd, BorrowedFd},
80 path::{Path, PathBuf},
81 sync::Arc,
82};
83
84use aya_obj::{
85 VerifierLog,
86 btf::BtfError,
87 generated::{bpf_attach_type, bpf_prog_info, bpf_prog_type},
88 programs::XdpAttachType,
89};
90use info::impl_info;
91pub use info::{LsmAttachType, ProgramInfo, ProgramType, loaded_programs};
92use libc::ENOSPC;
93use tc::SchedClassifierLink;
94use thiserror::Error;
95
96pub use crate::programs::{
98 cgroup_device::CgroupDevice,
99 cgroup_skb::{CgroupSkb, CgroupSkbAttachType},
100 cgroup_sock::{CgroupSock, CgroupSockAttachType},
101 cgroup_sock_addr::{CgroupSockAddr, CgroupSockAddrAttachType},
102 cgroup_sockopt::{CgroupSockopt, CgroupSockoptAttachType},
103 cgroup_sysctl::CgroupSysctl,
104 extension::{Extension, ExtensionError},
105 fentry::FEntry,
106 fexit::FExit,
107 flow_dissector::FlowDissector,
108 iter::Iter,
109 kprobe::{KProbe, KProbeError},
110 links::{CgroupAttachMode, Link, LinkOrder},
111 lirc_mode2::LircMode2,
112 lsm::Lsm,
113 lsm_cgroup::LsmCgroup,
114 perf_event::PerfEvent,
115 probe::ProbeKind,
116 raw_trace_point::RawTracePoint,
117 sk_lookup::SkLookup,
118 sk_msg::SkMsg,
119 sk_skb::{SkSkb, SkSkbKind},
120 sock_ops::SockOps,
121 socket_filter::{SocketFilter, SocketFilterError},
122 tc::{SchedClassifier, TcAttachType, TcError},
123 tp_btf::BtfTracePoint,
124 trace_point::{TracePoint, TracePointError},
125 uprobe::{UProbe, UProbeError},
126 xdp::{Xdp, XdpError, XdpFlags},
127};
128use crate::{
129 VerifierLogLevel,
130 maps::MapError,
131 pin::PinError,
132 programs::{
133 links::{
134 FdLink, FdLinkId, LinkError, LinkInfo, Links, ProgAttachLink, ProgAttachLinkId,
135 define_link_wrapper, id_as_key, impl_try_into_fdlink,
136 },
137 perf_attach::{PerfLinkIdInner, PerfLinkInner, perf_attach, perf_attach_debugfs},
138 },
139 sys::{
140 EbpfLoadProgramAttrs, NetlinkError, ProgQueryTarget, SyscallError, bpf_btf_get_fd_by_id,
141 bpf_get_object, bpf_link_get_fd_by_id, bpf_load_program, bpf_pin_object,
142 bpf_prog_get_fd_by_id, bpf_prog_query, iter_link_ids, retry_with_verifier_logs,
143 },
144 util::KernelVersion,
145};
146
147#[derive(Debug, Error)]
149pub enum ProgramError {
150 #[error("the program is already loaded")]
152 AlreadyLoaded,
153
154 #[error("the program is not loaded")]
156 NotLoaded,
157
158 #[error("the program was already attached")]
160 AlreadyAttached,
161
162 #[error("the program is not attached")]
164 NotAttached,
165
166 #[error("the BPF_PROG_LOAD syscall returned {io_error}. Verifier output: {verifier_log}")]
168 LoadError {
169 #[source]
171 io_error: io::Error,
172 verifier_log: VerifierLog,
174 },
175
176 #[error(transparent)]
178 SyscallError(#[from] SyscallError),
179
180 #[error("unknown network interface {name}")]
182 UnknownInterface {
183 name: String,
185 },
186
187 #[error("unexpected program type")]
189 UnexpectedProgramType,
190
191 #[error(transparent)]
193 MapError(#[from] MapError),
194
195 #[error(transparent)]
197 KProbeError(#[from] KProbeError),
198
199 #[error(transparent)]
201 UProbeError(#[from] UProbeError),
202
203 #[error(transparent)]
205 TracePointError(#[from] TracePointError),
206
207 #[error(transparent)]
209 SocketFilterError(#[from] SocketFilterError),
210
211 #[error(transparent)]
213 XdpError(#[from] XdpError),
214
215 #[error(transparent)]
217 TcError(#[from] TcError),
218
219 #[error(transparent)]
221 ExtensionError(#[from] ExtensionError),
222
223 #[error(transparent)]
225 Btf(#[from] BtfError),
226
227 #[error("the program name `{name}` is invalid")]
229 InvalidName {
230 name: String,
232 },
233
234 #[error(transparent)]
236 IOError(#[from] io::Error),
237
238 #[error("providing an attach cookie is not supported")]
240 AttachCookieNotSupported,
241
242 #[error(transparent)]
244 NetlinkError(#[from] NetlinkError),
245}
246
247#[derive(Debug)]
249pub struct ProgramFd(crate::MockableFd);
250
251impl ProgramFd {
252 pub fn try_clone(&self) -> io::Result<Self> {
254 let Self(inner) = self;
255 let inner = inner.try_clone()?;
256 Ok(Self(inner))
257 }
258}
259
260impl AsFd for ProgramFd {
261 fn as_fd(&self) -> BorrowedFd<'_> {
262 let Self(fd) = self;
263 fd.as_fd()
264 }
265}
266
267pub struct ProgramId(u32);
269
270impl ProgramId {
271 pub const unsafe fn new(id: u32) -> Self {
278 Self(id)
279 }
280}
281
282#[derive(Debug)]
284pub enum Program {
285 KProbe(KProbe),
287 UProbe(UProbe),
289 TracePoint(TracePoint),
291 SocketFilter(SocketFilter),
293 Xdp(Xdp),
295 SkMsg(SkMsg),
297 SkSkb(SkSkb),
299 CgroupSockAddr(CgroupSockAddr),
301 SockOps(SockOps),
303 SchedClassifier(SchedClassifier),
305 CgroupSkb(CgroupSkb),
307 CgroupSysctl(CgroupSysctl),
309 CgroupSockopt(CgroupSockopt),
311 LircMode2(LircMode2),
313 PerfEvent(PerfEvent),
315 RawTracePoint(RawTracePoint),
317 Lsm(Lsm),
319 LsmCgroup(LsmCgroup),
321 BtfTracePoint(BtfTracePoint),
323 FEntry(FEntry),
325 FExit(FExit),
327 FlowDissector(FlowDissector),
329 Extension(Extension),
331 SkLookup(SkLookup),
333 CgroupSock(CgroupSock),
335 CgroupDevice(CgroupDevice),
337 Iter(Iter),
339}
340
341impl Program {
342 pub const fn prog_type(&self) -> ProgramType {
344 match self {
345 Self::KProbe(_) | Self::UProbe(_) => ProgramType::KProbe,
346 Self::TracePoint(_) => ProgramType::TracePoint,
347 Self::SocketFilter(_) => ProgramType::SocketFilter,
348 Self::Xdp(_) => ProgramType::Xdp,
349 Self::SkMsg(_) => ProgramType::SkMsg,
350 Self::SkSkb(_) => ProgramType::SkSkb,
351 Self::SockOps(_) => ProgramType::SockOps,
352 Self::SchedClassifier(_) => ProgramType::SchedClassifier,
353 Self::CgroupSkb(_) => ProgramType::CgroupSkb,
354 Self::CgroupSysctl(_) => ProgramType::CgroupSysctl,
355 Self::CgroupSockopt(_) => ProgramType::CgroupSockopt,
356 Self::LircMode2(_) => ProgramType::LircMode2,
357 Self::PerfEvent(_) => ProgramType::PerfEvent,
358 Self::RawTracePoint(_) => ProgramType::RawTracePoint,
359 Self::Lsm(_) => ProgramType::Lsm(LsmAttachType::Mac),
360 Self::LsmCgroup(_) => ProgramType::Lsm(LsmAttachType::Cgroup),
361 Self::BtfTracePoint(_) | Self::FEntry(_) | Self::FExit(_) | Self::Iter(_) => {
371 ProgramType::Tracing
372 }
373 Self::Extension(_) => ProgramType::Extension,
374 Self::CgroupSockAddr(_) => ProgramType::CgroupSockAddr,
375 Self::SkLookup(_) => ProgramType::SkLookup,
376 Self::CgroupSock(_) => ProgramType::CgroupSock,
377 Self::CgroupDevice(_) => ProgramType::CgroupDevice,
378 Self::FlowDissector(_) => ProgramType::FlowDissector,
379 }
380 }
381
382 pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), PinError> {
384 match self {
385 Self::KProbe(p) => p.pin(path),
386 Self::UProbe(p) => p.pin(path),
387 Self::TracePoint(p) => p.pin(path),
388 Self::SocketFilter(p) => p.pin(path),
389 Self::Xdp(p) => p.pin(path),
390 Self::SkMsg(p) => p.pin(path),
391 Self::SkSkb(p) => p.pin(path),
392 Self::SockOps(p) => p.pin(path),
393 Self::SchedClassifier(p) => p.pin(path),
394 Self::CgroupSkb(p) => p.pin(path),
395 Self::CgroupSysctl(p) => p.pin(path),
396 Self::CgroupSockopt(p) => p.pin(path),
397 Self::LircMode2(p) => p.pin(path),
398 Self::PerfEvent(p) => p.pin(path),
399 Self::RawTracePoint(p) => p.pin(path),
400 Self::Lsm(p) => p.pin(path),
401 Self::LsmCgroup(p) => p.pin(path),
402 Self::BtfTracePoint(p) => p.pin(path),
403 Self::FEntry(p) => p.pin(path),
404 Self::FExit(p) => p.pin(path),
405 Self::FlowDissector(p) => p.pin(path),
406 Self::Extension(p) => p.pin(path),
407 Self::CgroupSockAddr(p) => p.pin(path),
408 Self::SkLookup(p) => p.pin(path),
409 Self::CgroupSock(p) => p.pin(path),
410 Self::CgroupDevice(p) => p.pin(path),
411 Self::Iter(p) => p.pin(path),
412 }
413 }
414
415 pub fn unload(self) -> Result<(), ProgramError> {
417 match self {
418 Self::KProbe(mut p) => p.unload(),
419 Self::UProbe(mut p) => p.unload(),
420 Self::TracePoint(mut p) => p.unload(),
421 Self::SocketFilter(mut p) => p.unload(),
422 Self::Xdp(mut p) => p.unload(),
423 Self::SkMsg(mut p) => p.unload(),
424 Self::SkSkb(mut p) => p.unload(),
425 Self::SockOps(mut p) => p.unload(),
426 Self::SchedClassifier(mut p) => p.unload(),
427 Self::CgroupSkb(mut p) => p.unload(),
428 Self::CgroupSysctl(mut p) => p.unload(),
429 Self::CgroupSockopt(mut p) => p.unload(),
430 Self::LircMode2(mut p) => p.unload(),
431 Self::PerfEvent(mut p) => p.unload(),
432 Self::RawTracePoint(mut p) => p.unload(),
433 Self::Lsm(mut p) => p.unload(),
434 Self::LsmCgroup(mut p) => p.unload(),
435 Self::BtfTracePoint(mut p) => p.unload(),
436 Self::FEntry(mut p) => p.unload(),
437 Self::FExit(mut p) => p.unload(),
438 Self::FlowDissector(mut p) => p.unload(),
439 Self::Extension(mut p) => p.unload(),
440 Self::CgroupSockAddr(mut p) => p.unload(),
441 Self::SkLookup(mut p) => p.unload(),
442 Self::CgroupSock(mut p) => p.unload(),
443 Self::CgroupDevice(mut p) => p.unload(),
444 Self::Iter(mut p) => p.unload(),
445 }
446 }
447
448 pub fn fd(&self) -> Result<&ProgramFd, ProgramError> {
452 match self {
453 Self::KProbe(p) => p.fd(),
454 Self::UProbe(p) => p.fd(),
455 Self::TracePoint(p) => p.fd(),
456 Self::SocketFilter(p) => p.fd(),
457 Self::Xdp(p) => p.fd(),
458 Self::SkMsg(p) => p.fd(),
459 Self::SkSkb(p) => p.fd(),
460 Self::SockOps(p) => p.fd(),
461 Self::SchedClassifier(p) => p.fd(),
462 Self::CgroupSkb(p) => p.fd(),
463 Self::CgroupSysctl(p) => p.fd(),
464 Self::CgroupSockopt(p) => p.fd(),
465 Self::LircMode2(p) => p.fd(),
466 Self::PerfEvent(p) => p.fd(),
467 Self::RawTracePoint(p) => p.fd(),
468 Self::Lsm(p) => p.fd(),
469 Self::LsmCgroup(p) => p.fd(),
470 Self::BtfTracePoint(p) => p.fd(),
471 Self::FEntry(p) => p.fd(),
472 Self::FExit(p) => p.fd(),
473 Self::FlowDissector(p) => p.fd(),
474 Self::Extension(p) => p.fd(),
475 Self::CgroupSockAddr(p) => p.fd(),
476 Self::SkLookup(p) => p.fd(),
477 Self::CgroupSock(p) => p.fd(),
478 Self::CgroupDevice(p) => p.fd(),
479 Self::Iter(p) => p.fd(),
480 }
481 }
482
483 pub fn info(&self) -> Result<ProgramInfo, ProgramError> {
488 match self {
489 Self::KProbe(p) => p.info(),
490 Self::UProbe(p) => p.info(),
491 Self::TracePoint(p) => p.info(),
492 Self::SocketFilter(p) => p.info(),
493 Self::Xdp(p) => p.info(),
494 Self::SkMsg(p) => p.info(),
495 Self::SkSkb(p) => p.info(),
496 Self::SockOps(p) => p.info(),
497 Self::SchedClassifier(p) => p.info(),
498 Self::CgroupSkb(p) => p.info(),
499 Self::CgroupSysctl(p) => p.info(),
500 Self::CgroupSockopt(p) => p.info(),
501 Self::LircMode2(p) => p.info(),
502 Self::PerfEvent(p) => p.info(),
503 Self::RawTracePoint(p) => p.info(),
504 Self::Lsm(p) => p.info(),
505 Self::LsmCgroup(p) => p.info(),
506 Self::BtfTracePoint(p) => p.info(),
507 Self::FEntry(p) => p.info(),
508 Self::FExit(p) => p.info(),
509 Self::FlowDissector(p) => p.info(),
510 Self::Extension(p) => p.info(),
511 Self::CgroupSockAddr(p) => p.info(),
512 Self::SkLookup(p) => p.info(),
513 Self::CgroupSock(p) => p.info(),
514 Self::CgroupDevice(p) => p.info(),
515 Self::Iter(p) => p.info(),
516 }
517 }
518}
519
520#[derive(Debug)]
521pub(crate) struct ProgramData<T: Link> {
522 pub(crate) name: Option<Cow<'static, str>>,
523 pub(crate) obj: Option<(aya_obj::Program, aya_obj::Function)>,
524 pub(crate) fd: Option<ProgramFd>,
525 pub(crate) links: Links<T>,
526 pub(crate) expected_attach_type: Option<bpf_attach_type>,
527 pub(crate) attach_btf_obj_fd: Option<crate::MockableFd>,
528 pub(crate) attach_btf_id: Option<u32>,
529 pub(crate) attach_prog_fd: Option<ProgramFd>,
530 pub(crate) btf_fd: Option<Arc<crate::MockableFd>>,
531 pub(crate) verifier_log_level: VerifierLogLevel,
532 pub(crate) path: Option<PathBuf>,
533 pub(crate) flags: u32,
534}
535
536impl<T: Link> ProgramData<T> {
537 pub(crate) fn new(
538 name: Option<Cow<'static, str>>,
539 obj: (aya_obj::Program, aya_obj::Function),
540 btf_fd: Option<Arc<crate::MockableFd>>,
541 verifier_log_level: VerifierLogLevel,
542 ) -> Self {
543 Self {
544 name,
545 obj: Some(obj),
546 fd: None,
547 links: Links::new(),
548 expected_attach_type: None,
549 attach_btf_obj_fd: None,
550 attach_btf_id: None,
551 attach_prog_fd: None,
552 btf_fd,
553 verifier_log_level,
554 path: None,
555 flags: 0,
556 }
557 }
558
559 pub(crate) fn from_bpf_prog_info(
560 name: Option<Cow<'static, str>>,
561 fd: crate::MockableFd,
562 path: &Path,
563 info: bpf_prog_info,
564 verifier_log_level: VerifierLogLevel,
565 ) -> Result<Self, ProgramError> {
566 let attach_btf_id = (info.attach_btf_id > 0).then_some(info.attach_btf_id);
567 let attach_btf_obj_fd = (info.attach_btf_obj_id != 0)
568 .then(|| bpf_btf_get_fd_by_id(info.attach_btf_obj_id))
569 .transpose()?;
570
571 Ok(Self {
572 name,
573 obj: None,
574 fd: Some(ProgramFd(fd)),
575 links: Links::new(),
576 expected_attach_type: None,
577 attach_btf_obj_fd,
578 attach_btf_id,
579 attach_prog_fd: None,
580 btf_fd: None,
581 verifier_log_level,
582 path: Some(path.to_path_buf()),
583 flags: 0,
584 })
585 }
586
587 pub(crate) fn from_pinned_path<P: AsRef<Path>>(
588 path: P,
589 verifier_log_level: VerifierLogLevel,
590 ) -> Result<Self, ProgramError> {
591 use std::os::unix::ffi::OsStrExt as _;
592
593 let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
595 let fd = bpf_get_object(&path_string).map_err(|io_error| SyscallError {
596 call: "bpf_obj_get",
597 io_error,
598 })?;
599
600 let info = ProgramInfo::new_from_fd(fd.as_fd())?;
601 let name = info.name_as_str().map(ToOwned::to_owned).map(Into::into);
602 Self::from_bpf_prog_info(name, fd, path.as_ref(), info.0, verifier_log_level)
603 }
604}
605
606impl<T: Link> ProgramData<T> {
607 fn fd(&self) -> Result<&ProgramFd, ProgramError> {
608 self.fd.as_ref().ok_or(ProgramError::NotLoaded)
609 }
610}
611
612fn unload_program<T: Link>(data: &mut ProgramData<T>) -> Result<(), ProgramError> {
613 data.links.remove_all()?;
614 data.fd
615 .take()
616 .ok_or(ProgramError::NotLoaded)
617 .map(|ProgramFd { .. }| ())
618}
619
620fn pin_program<T: Link, P: AsRef<Path>>(data: &ProgramData<T>, path: P) -> Result<(), PinError> {
621 use std::os::unix::ffi::OsStrExt as _;
622
623 let fd = data.fd.as_ref().ok_or_else(|| PinError::NoFd {
624 name: data
625 .name
626 .as_deref()
627 .unwrap_or("<unknown program>")
628 .to_string(),
629 })?;
630 let path = path.as_ref();
631 let path_string =
632 CString::new(path.as_os_str().as_bytes()).map_err(|error| PinError::InvalidPinPath {
633 path: path.into(),
634 error,
635 })?;
636 bpf_pin_object(fd.as_fd(), &path_string).map_err(|io_error| SyscallError {
637 call: "BPF_OBJ_PIN",
638 io_error,
639 })?;
640 Ok(())
641}
642
643fn load_program<T: Link>(
644 prog_type: bpf_prog_type,
645 data: &mut ProgramData<T>,
646) -> Result<(), ProgramError> {
647 let ProgramData {
648 name,
649 obj,
650 fd,
651 links: _,
652 expected_attach_type,
653 attach_btf_obj_fd,
654 attach_btf_id,
655 attach_prog_fd,
656 btf_fd,
657 verifier_log_level,
658 path: _,
659 flags,
660 } = data;
661 if fd.is_some() {
662 return Err(ProgramError::AlreadyLoaded);
663 }
664 if obj.is_none() {
665 return Err(ProgramError::AlreadyLoaded);
667 }
668 let obj = obj.as_ref().unwrap();
669 let (
670 aya_obj::Program {
671 license,
672 kernel_version,
673 ..
674 },
675 aya_obj::Function {
676 instructions,
677 func_info,
678 line_info,
679 func_info_rec_size,
680 line_info_rec_size,
681 ..
682 },
683 ) = obj;
684
685 let target_kernel_version =
686 kernel_version.unwrap_or_else(|| KernelVersion::current().map_or(0, KernelVersion::code));
687
688 let prog_name = if let Some(name) = name.as_deref() {
689 let prog_name = CString::new(name).map_err(|err @ std::ffi::NulError { .. }| {
690 let name = err.into_vec();
691 let name = unsafe { String::from_utf8_unchecked(name) };
692 ProgramError::InvalidName { name }
693 })?;
694 Some(prog_name)
695 } else {
696 None
697 };
698
699 let attr = EbpfLoadProgramAttrs {
700 name: prog_name,
701 ty: prog_type,
702 insns: instructions,
703 license,
704 kernel_version: target_kernel_version,
705 expected_attach_type: *expected_attach_type,
706 prog_btf_fd: btf_fd.as_ref().map(|f| f.as_fd()),
707 attach_btf_obj_fd: attach_btf_obj_fd.as_ref().map(|fd| fd.as_fd()),
708 attach_btf_id: *attach_btf_id,
709 attach_prog_fd: attach_prog_fd.as_ref().map(|fd| fd.as_fd()),
710 func_info_rec_size: *func_info_rec_size,
711 func_info: func_info.clone(),
712 line_info_rec_size: *line_info_rec_size,
713 line_info: line_info.clone(),
714 flags: *flags,
715 };
716
717 let (ret, verifier_log) = retry_with_verifier_logs(10, |logger| {
718 bpf_load_program(&attr, logger, *verifier_log_level)
719 });
720
721 match ret {
722 Ok(prog_fd) => {
723 *fd = Some(ProgramFd(prog_fd));
724 Ok(())
725 }
726 Err(io_error) => Err(ProgramError::LoadError {
727 io_error,
728 verifier_log,
729 }),
730 }
731}
732
733pub(crate) fn query(
734 target: ProgQueryTarget<'_>,
735 attach_type: bpf_attach_type,
736 query_flags: u32,
737 attach_flags: &mut Option<u32>,
738) -> Result<(u64, Vec<u32>), ProgramError> {
739 let mut prog_ids = vec![0u32; 64];
740 let mut prog_cnt = prog_ids.len() as u32;
741 let mut revision = 0;
742
743 let mut retries = 0;
744
745 loop {
746 match bpf_prog_query(
747 &target,
748 attach_type,
749 query_flags,
750 attach_flags.as_mut(),
751 &mut prog_ids,
752 &mut prog_cnt,
753 &mut revision,
754 ) {
755 Ok(()) => {
756 prog_ids.resize(prog_cnt as usize, 0);
757 return Ok((revision, prog_ids));
758 }
759 Err(io_error) => {
760 if retries == 0 && io_error.raw_os_error() == Some(ENOSPC) {
761 prog_ids.resize(prog_cnt as usize, 0);
762 retries += 1;
763 } else {
764 return Err(SyscallError {
765 call: "bpf_prog_query",
766 io_error,
767 }
768 .into());
769 }
770 }
771 }
772 }
773}
774
775macro_rules! impl_program_unload {
776 ($($struct_name:ident),+ $(,)?) => {
777 $(
778 impl $struct_name {
779 pub fn unload(&mut self) -> Result<(), ProgramError> {
785 unload_program(&mut self.data)
786 }
787 }
788
789 impl Drop for $struct_name {
790 fn drop(&mut self) {
791 let _unused: Result<(), ProgramError> = self.unload();
792 }
793 }
794 )+
795 }
796}
797
798impl_program_unload!(
799 KProbe,
800 UProbe,
801 TracePoint,
802 SocketFilter,
803 Xdp,
804 SkMsg,
805 SkSkb,
806 SchedClassifier,
807 CgroupSkb,
808 CgroupSysctl,
809 CgroupSockopt,
810 LircMode2,
811 PerfEvent,
812 Lsm,
813 LsmCgroup,
814 RawTracePoint,
815 BtfTracePoint,
816 FEntry,
817 FExit,
818 FlowDissector,
819 Extension,
820 CgroupSockAddr,
821 SkLookup,
822 SockOps,
823 CgroupSock,
824 CgroupDevice,
825 Iter,
826);
827
828macro_rules! impl_fd {
829 ($($struct_name:ident),+ $(,)?) => {
830 $(
831 impl $struct_name {
832 pub fn fd(&self) -> Result<&ProgramFd, ProgramError> {
834 self.data.fd()
835 }
836 }
837 )+
838 }
839}
840
841impl_fd!(
842 KProbe,
843 UProbe,
844 TracePoint,
845 SocketFilter,
846 Xdp,
847 SkMsg,
848 SkSkb,
849 SchedClassifier,
850 CgroupSkb,
851 CgroupSysctl,
852 CgroupSockopt,
853 LircMode2,
854 PerfEvent,
855 Lsm,
856 LsmCgroup,
857 RawTracePoint,
858 BtfTracePoint,
859 FEntry,
860 FExit,
861 FlowDissector,
862 Extension,
863 CgroupSockAddr,
864 SkLookup,
865 SockOps,
866 CgroupSock,
867 CgroupDevice,
868 Iter,
869);
870
871pub trait MultiProgram {
878 fn fd(&self) -> Result<BorrowedFd<'_>, ProgramError>;
880}
881
882macro_rules! impl_multiprog_fd {
883 ($($struct_name:ident),+ $(,)?) => {
884 $(
885 impl MultiProgram for $struct_name {
886 fn fd(&self) -> Result<BorrowedFd<'_>, ProgramError> {
887 Ok(self.fd()?.as_fd())
888 }
889 }
890 )+
891 }
892}
893
894impl_multiprog_fd!(SchedClassifier);
895
896pub trait MultiProgLink {
903 fn fd(&self) -> Result<BorrowedFd<'_>, LinkError>;
905}
906
907macro_rules! impl_multiproglink_fd {
908 ($($struct_name:ident),+ $(,)?) => {
909 $(
910 impl MultiProgLink for $struct_name {
911 fn fd(&self) -> Result<BorrowedFd<'_>, LinkError> {
912 let link: &FdLink = self.try_into()?;
913 Ok(link.fd.as_fd())
914 }
915 }
916 )+
917 }
918}
919
920impl_multiproglink_fd!(SchedClassifierLink);
921
922macro_rules! impl_program_pin{
923 ($($struct_name:ident),+ $(,)?) => {
924 $(
925 impl $struct_name {
926 pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), PinError> {
933 self.data.path = Some(path.as_ref().to_path_buf());
934 pin_program(&self.data, path)
935 }
936
937 pub fn unpin(&mut self) -> Result<(), io::Error> {
939 if let Some(path) = self.data.path.take() {
940 std::fs::remove_file(path)?;
941 }
942 Ok(())
943 }
944 }
945 )+
946 }
947}
948
949impl_program_pin!(
950 KProbe,
951 UProbe,
952 TracePoint,
953 SocketFilter,
954 Xdp,
955 SkMsg,
956 SkSkb,
957 SchedClassifier,
958 CgroupSkb,
959 CgroupSysctl,
960 CgroupSockopt,
961 LircMode2,
962 PerfEvent,
963 Lsm,
964 LsmCgroup,
965 RawTracePoint,
966 BtfTracePoint,
967 FEntry,
968 FExit,
969 FlowDissector,
970 Extension,
971 CgroupSockAddr,
972 SkLookup,
973 SockOps,
974 CgroupSock,
975 CgroupDevice,
976 Iter,
977);
978
979macro_rules! impl_from_pin {
980 ($($struct_name:ident),+ $(,)?) => {
981 $(
982 impl $struct_name {
983 pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, ProgramError> {
990 let data = ProgramData::from_pinned_path(path, VerifierLogLevel::default())?;
991 Ok(Self { data })
992 }
993 }
994 )+
995 }
996}
997
998impl_from_pin!(
1000 TracePoint,
1001 SocketFilter,
1002 SkMsg,
1003 CgroupSysctl,
1004 LircMode2,
1005 Lsm,
1006 PerfEvent,
1007 RawTracePoint,
1008 BtfTracePoint,
1009 FEntry,
1010 FExit,
1011 FlowDissector,
1012 Extension,
1013 SkLookup,
1014 SockOps,
1015 CgroupDevice,
1016 Iter,
1017);
1018
1019macro_rules! impl_from_prog_info {
1020 (
1021 $(#[$doc:meta])*
1022 @safety
1023 [$($safety:tt)?]
1024 @rest
1025 $struct_name:ident $($var:ident : $var_ty:ty)?
1026 ) => {
1027 impl $struct_name {
1028 $(#[$doc])*
1039 pub $($safety)?
1040 fn from_program_info(
1041 info: ProgramInfo,
1042 name: Cow<'static, str>,
1043 $($var: $var_ty,)?
1044 ) -> Result<Self, ProgramError> {
1045 if info.program_type() != Self::PROGRAM_TYPE.into() {
1046 return Err(ProgramError::UnexpectedProgramType {});
1047 }
1048 let ProgramInfo(bpf_progam_info) = info;
1049 let fd = info.fd()?;
1050 let fd = fd.as_fd().try_clone_to_owned()?;
1051
1052 Ok(Self {
1053 data: ProgramData::from_bpf_prog_info(
1054 Some(name),
1055 crate::MockableFd::from_fd(fd),
1056 Path::new(""),
1057 bpf_progam_info,
1058 VerifierLogLevel::default(),
1059 )?,
1060 $($var,)?
1061 })
1062 }
1063 }
1064 };
1065
1066 (
1068 unsafe $struct_name:ident $($var:ident : $var_ty:ty)? $(, $($rest:tt)*)?
1069 ) => {
1070 impl_from_prog_info! {
1071 @safety [unsafe]
1080 @rest $struct_name $($var : $var_ty)?
1081 }
1082 $( impl_from_prog_info!($($rest)*); )?
1083 };
1084
1085 (
1087 $struct_name:ident $($var:ident : $var_ty:ty)? $(, $($rest:tt)*)?
1088 ) => {
1089 impl_from_prog_info! {
1090 @safety []
1091 @rest $struct_name $($var : $var_ty)?
1092 }
1093 $( impl_from_prog_info!($($rest)*); )?
1094 };
1095
1096 (
1098 $(,)?
1099 ) => {};
1100}
1101
1102impl_from_prog_info!(
1103 unsafe KProbe kind : ProbeKind,
1104 unsafe UProbe kind : ProbeKind,
1105 TracePoint,
1106 Xdp attach_type : XdpAttachType,
1107 SkMsg,
1108 SkSkb kind : SkSkbKind,
1109 SockOps,
1110 SchedClassifier,
1111 CgroupSkb attach_type : Option<CgroupSkbAttachType>,
1112 CgroupSysctl,
1113 CgroupSockopt attach_type : CgroupSockoptAttachType,
1114 LircMode2,
1115 PerfEvent,
1116 Lsm,
1117 RawTracePoint,
1118 unsafe BtfTracePoint,
1119 unsafe FEntry,
1120 unsafe FExit,
1121 Extension,
1122 SkLookup,
1123 CgroupDevice,
1124 Iter,
1125);
1126
1127macro_rules! impl_try_from_program {
1128 ($($ty:ident),+ $(,)?) => {
1129 $(
1130 impl<'a> TryFrom<&'a Program> for &'a $ty {
1131 type Error = ProgramError;
1132
1133 fn try_from(program: &'a Program) -> Result<&'a $ty, ProgramError> {
1134 match program {
1135 Program::$ty(p) => Ok(p),
1136 _ => Err(ProgramError::UnexpectedProgramType),
1137 }
1138 }
1139 }
1140
1141 impl<'a> TryFrom<&'a mut Program> for &'a mut $ty {
1142 type Error = ProgramError;
1143
1144 fn try_from(program: &'a mut Program) -> Result<&'a mut $ty, ProgramError> {
1145 match program {
1146 Program::$ty(p) => Ok(p),
1147 _ => Err(ProgramError::UnexpectedProgramType),
1148 }
1149 }
1150 }
1151 )+
1152 }
1153}
1154
1155impl_try_from_program!(
1156 KProbe,
1157 UProbe,
1158 TracePoint,
1159 SocketFilter,
1160 Xdp,
1161 SkMsg,
1162 SkSkb,
1163 SockOps,
1164 SchedClassifier,
1165 CgroupSkb,
1166 CgroupSysctl,
1167 CgroupSockopt,
1168 LircMode2,
1169 PerfEvent,
1170 Lsm,
1171 LsmCgroup,
1172 RawTracePoint,
1173 BtfTracePoint,
1174 FEntry,
1175 FExit,
1176 FlowDissector,
1177 Extension,
1178 CgroupSockAddr,
1179 SkLookup,
1180 CgroupSock,
1181 CgroupDevice,
1182 Iter,
1183);
1184
1185impl_info!(
1186 KProbe,
1187 UProbe,
1188 TracePoint,
1189 SocketFilter,
1190 Xdp,
1191 SkMsg,
1192 SkSkb,
1193 SchedClassifier,
1194 CgroupSkb,
1195 CgroupSysctl,
1196 CgroupSockopt,
1197 LircMode2,
1198 PerfEvent,
1199 Lsm,
1200 LsmCgroup,
1201 RawTracePoint,
1202 BtfTracePoint,
1203 FEntry,
1204 FExit,
1205 FlowDissector,
1206 Extension,
1207 CgroupSockAddr,
1208 SkLookup,
1209 SockOps,
1210 CgroupSock,
1211 CgroupDevice,
1212 Iter,
1213);
1214
1215pub fn loaded_links() -> impl Iterator<Item = Result<LinkInfo, LinkError>> {
1237 iter_link_ids()
1238 .map(|id| {
1239 let id = id?;
1240 bpf_link_get_fd_by_id(id)
1241 })
1242 .map(|fd| {
1243 let fd = fd?;
1244 LinkInfo::new_from_fd(fd.as_fd())
1245 })
1246}