aya/programs/
sk_skb.rs

1//! Skskb programs.
2
3use std::{os::fd::AsFd as _, path::Path};
4
5use crate::{
6    generated::{
7        bpf_attach_type::{BPF_SK_SKB_STREAM_PARSER, BPF_SK_SKB_STREAM_VERDICT},
8        bpf_prog_type::BPF_PROG_TYPE_SK_SKB,
9    },
10    maps::sock::SockMapFd,
11    programs::{
12        define_link_wrapper, load_program, CgroupAttachMode, ProgAttachLink, ProgAttachLinkId,
13        ProgramData, ProgramError,
14    },
15    VerifierLogLevel,
16};
17
18/// The kind of [`SkSkb`] program.
19#[derive(Copy, Clone, Debug)]
20pub enum SkSkbKind {
21    /// A Stream Parser
22    StreamParser,
23    /// A Stream Verdict
24    StreamVerdict,
25}
26
27/// A program used to intercept ingress socket buffers.
28///
29/// [`SkSkb`] programs are attached to [socket maps], and can be used to
30/// inspect, redirect or filter incoming packet. See also [`SockMap`] and
31/// [`SockHash`].
32///
33/// # Minimum kernel version
34///
35/// The minimum kernel version required to use this feature is 4.14.
36///
37/// # Examples
38///
39/// ```no_run
40/// # #[derive(Debug, thiserror::Error)]
41/// # enum Error {
42/// #     #[error(transparent)]
43/// #     IO(#[from] std::io::Error),
44/// #     #[error(transparent)]
45/// #     Map(#[from] aya::maps::MapError),
46/// #     #[error(transparent)]
47/// #     Program(#[from] aya::programs::ProgramError),
48/// #     #[error(transparent)]
49/// #     Ebpf(#[from] aya::EbpfError)
50/// # }
51/// # let mut bpf = aya::Ebpf::load(&[])?;
52/// use aya::maps::SockMap;
53/// use aya::programs::SkSkb;
54///
55/// let intercept_ingress: SockMap<_> = bpf.map("INTERCEPT_INGRESS").unwrap().try_into()?;
56/// let map_fd = intercept_ingress.fd().try_clone()?;
57///
58/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?;
59/// prog.load()?;
60/// prog.attach(&map_fd)?;
61///
62/// # Ok::<(), Error>(())
63/// ```
64///
65/// [socket maps]: crate::maps::sock
66/// [`SockMap`]: crate::maps::SockMap
67/// [`SockHash`]: crate::maps::SockHash
68#[derive(Debug)]
69#[doc(alias = "BPF_PROG_TYPE_SK_SKB")]
70pub struct SkSkb {
71    pub(crate) data: ProgramData<SkSkbLink>,
72    pub(crate) kind: SkSkbKind,
73}
74
75impl SkSkb {
76    /// Loads the program inside the kernel.
77    pub fn load(&mut self) -> Result<(), ProgramError> {
78        load_program(BPF_PROG_TYPE_SK_SKB, &mut self.data)
79    }
80
81    /// Attaches the program to the given socket map.
82    ///
83    /// The returned value can be used to detach, see [SkSkb::detach].
84    pub fn attach(&mut self, map: &SockMapFd) -> Result<SkSkbLinkId, ProgramError> {
85        let prog_fd = self.fd()?;
86        let prog_fd = prog_fd.as_fd();
87
88        let attach_type = match self.kind {
89            SkSkbKind::StreamParser => BPF_SK_SKB_STREAM_PARSER,
90            SkSkbKind::StreamVerdict => BPF_SK_SKB_STREAM_VERDICT,
91        };
92
93        let link =
94            ProgAttachLink::attach(prog_fd, map.as_fd(), attach_type, CgroupAttachMode::Single)?;
95
96        self.data.links.insert(SkSkbLink::new(link))
97    }
98
99    /// Detaches the program.
100    ///
101    /// See [SkSkb::attach].
102    pub fn detach(&mut self, link_id: SkSkbLinkId) -> Result<(), ProgramError> {
103        self.data.links.remove(link_id)
104    }
105
106    /// Takes ownership of the link referenced by the provided link_id.
107    ///
108    /// The link will be detached on `Drop` and the caller is now responsible
109    /// for managing its lifetime.
110    pub fn take_link(&mut self, link_id: SkSkbLinkId) -> Result<SkSkbLink, ProgramError> {
111        self.data.take_link(link_id)
112    }
113
114    /// Creates a program from a pinned entry on a bpffs.
115    ///
116    /// Existing links will not be populated. To work with existing links you should use [`crate::programs::links::PinnedLink`].
117    ///
118    /// On drop, any managed links are detached and the program is unloaded. This will not result in
119    /// the program being unloaded from the kernel if it is still pinned.
120    pub fn from_pin<P: AsRef<Path>>(path: P, kind: SkSkbKind) -> Result<Self, ProgramError> {
121        let data = ProgramData::from_pinned_path(path, VerifierLogLevel::default())?;
122        Ok(Self { data, kind })
123    }
124}
125
126define_link_wrapper!(
127    /// The link used by [SkSkb] programs.
128    SkSkbLink,
129    /// The type returned by [SkSkb::attach]. Can be passed to [SkSkb::detach].
130    SkSkbLinkId,
131    ProgAttachLink,
132    ProgAttachLinkId
133);