Browse Source

aya: programs: add support for BPF_PROG_TYPE_CGROUP_SKB programs

Alessandro Decina 3 years ago
parent
commit
08a68faf8a
4 changed files with 142 additions and 6 deletions
  1. 10 2
      aya/src/bpf.rs
  2. 8 1
      aya/src/obj/mod.rs
  3. 114 0
      aya/src/programs/cgroup_skb.rs
  4. 10 3
      aya/src/programs/mod.rs

+ 10 - 2
aya/src/bpf.rs

@@ -19,8 +19,8 @@ use crate::{
         Object, ParseError, ProgramKind,
     },
     programs::{
-        KProbe, ProbeKind, Program, ProgramData, ProgramError, SchedClassifier, SkMsg, SkSkb,
-        SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp,
+        CgroupSkb, CgroupSkbAttachType, KProbe, ProbeKind, Program, ProgramData, ProgramError,
+        SchedClassifier, SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp,
     },
     sys::bpf_map_update_elem_ptr,
     util::{possible_cpus, POSSIBLE_CPUS},
@@ -187,6 +187,14 @@ impl Bpf {
                     ProgramKind::SchedClassifier => {
                         Program::SchedClassifier(SchedClassifier { data })
                     }
+                    ProgramKind::CgroupSkbIngress => Program::CgroupSkb(CgroupSkb {
+                        data,
+                        expected_attach_type: Some(CgroupSkbAttachType::Ingress),
+                    }),
+                    ProgramKind::CgroupSkbEgress => Program::CgroupSkb(CgroupSkb {
+                        data,
+                        expected_attach_type: Some(CgroupSkbAttachType::Egress),
+                    }),
                 };
 
                 (name, program)

+ 8 - 1
aya/src/obj/mod.rs

@@ -78,6 +78,8 @@ pub enum ProgramKind {
     SkSkbStreamVerdict,
     SockOps,
     SchedClassifier,
+    CgroupSkbIngress,
+    CgroupSkbEgress,
 }
 
 impl FromStr for ProgramKind {
@@ -98,6 +100,8 @@ impl FromStr for ProgramKind {
             "sk_skb/stream_verdict" => SkSkbStreamVerdict,
             "sockops" => SockOps,
             "classifier" => SchedClassifier,
+            "cgroup_skb/ingress" => CgroupSkbIngress,
+            "cgroup_skb/egress" => CgroupSkbEgress,
             _ => {
                 return Err(ParseError::InvalidProgramKind {
                     kind: kind.to_string(),
@@ -295,7 +299,10 @@ impl Object {
             | &[ty @ "sk_skb/stream_parser", name]
             | &[ty @ "sk_skb/stream_verdict", name]
             | &[ty @ "sockops", name]
-            | &[ty @ "classifier", name] => {
+            | &[ty @ "classifier", name]
+            | &[ty @ "cgroup_skb/ingress", name]
+            | &[ty @ "cgroup_skb/egress", name]
+            | &[ty @ "cgroup/skb", name] => {
                 self.programs
                     .insert(name.to_string(), self.parse_program(&section, ty, name)?);
                 if !section.relocations.is_empty() {

+ 114 - 0
aya/src/programs/cgroup_skb.rs

@@ -0,0 +1,114 @@
+use std::os::unix::prelude::{AsRawFd, RawFd};
+
+use crate::{
+    generated::{
+        bpf_attach_type::{BPF_CGROUP_INET_EGRESS, BPF_CGROUP_INET_INGRESS},
+        bpf_prog_type::BPF_PROG_TYPE_CGROUP_SKB,
+    },
+    programs::{load_program, LinkRef, ProgAttachLink, ProgramData, ProgramError},
+    sys::{bpf_link_create, bpf_prog_attach, kernel_version},
+};
+
+use super::FdLink;
+
+/// A program used to inspect or filter network activity for a given cgroup.
+///
+/// [`CgroupSkb`] programs can be used to inspect or filter network activity
+/// generated on all the sockets belonging to a given [cgroup].
+///
+/// [cgroup]: https://man7.org/linux/man-pages/man7/cgroups.7.html
+#[derive(Debug)]
+pub struct CgroupSkb {
+    pub(crate) data: ProgramData,
+    pub(crate) expected_attach_type: Option<CgroupSkbAttachType>,
+}
+
+impl CgroupSkb {
+    /// Loads the program inside the kernel.
+    ///
+    /// See also [`Program::load`](crate::programs::Program::load).
+    pub fn load(&mut self) -> Result<(), ProgramError> {
+        load_program(BPF_PROG_TYPE_CGROUP_SKB, &mut self.data)
+    }
+
+    /// Returns the name of the program.
+    pub fn name(&self) -> String {
+        self.data.name.to_string()
+    }
+
+    /// Returns the expected attach type of the program.
+    ///
+    /// [`CgroupSkb`] programs can specify the expected attach type in their ELF
+    /// section name, eg `cgroup_skb/ingress` or `cgroup_skb/egress`. This
+    /// method returns `None` for programs defined with the generic section
+    /// `cgroup/skb`.
+    pub fn expected_attach_type(&self) -> &Option<CgroupSkbAttachType> {
+        &self.expected_attach_type
+    }
+
+    /// Attaches the program to the given cgroup.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// # #[derive(thiserror::Error, Debug)]
+    /// # enum Error {
+    /// #     #[error(transparent)]
+    /// #     IO(#[from] std::io::Error),
+    /// #     #[error(transparent)]
+    /// #     Map(#[from] aya::maps::MapError),
+    /// #     #[error(transparent)]
+    /// #     Bpf(#[from] aya::BpfError)
+    /// # }
+    /// # let bpf = aya::Bpf::load(&[], None)?;
+    /// use aya::programs::{CgroupSkb, CgroupSkbAttachType};
+    ///
+    /// let file = File::open("/sys/fs/cgroup/unified")?;
+    /// let egress: &mut CgroupSkb =
+    ///     self.bpf.program_mut("egress_filter")?.try_into()?;
+    /// egress.load()?;
+    /// egress.attach(file, CgroupSkbAttachType::Egress)?;
+    /// # Ok::<(), Error>(())
+    /// ```
+    pub fn attach<T: AsRawFd>(
+        &mut self,
+        cgroup: T,
+        attach_type: CgroupSkbAttachType,
+    ) -> Result<LinkRef, ProgramError> {
+        let prog_fd = self.data.fd_or_err()?;
+        let cgroup_fd = cgroup.as_raw_fd();
+
+        let attach_type = match attach_type {
+            CgroupSkbAttachType::Ingress => BPF_CGROUP_INET_INGRESS,
+            CgroupSkbAttachType::Egress => BPF_CGROUP_INET_EGRESS,
+        };
+        let k_ver = kernel_version().unwrap();
+        if k_ver >= (5, 7, 0) {
+            let link_fd =
+                bpf_link_create(prog_fd, cgroup_fd, attach_type, 0).map_err(|(_, io_error)| {
+                    ProgramError::SyscallError {
+                        call: "bpf_link_create".to_owned(),
+                        io_error,
+                    }
+                })? as RawFd;
+            Ok(self.data.link(FdLink { fd: Some(link_fd) }))
+        } else {
+            bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| {
+                ProgramError::SyscallError {
+                    call: "bpf_prog_attach".to_owned(),
+                    io_error,
+                }
+            })?;
+
+            Ok(self
+                .data
+                .link(ProgAttachLink::new(prog_fd, cgroup_fd, attach_type)))
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum CgroupSkbAttachType {
+    Ingress,
+    Egress,
+}

+ 10 - 3
aya/src/programs/mod.rs

@@ -44,7 +44,7 @@
 //! [`Bpf::program`]: crate::Bpf::program
 //! [`Bpf::program_mut`]: crate::Bpf::program_mut
 //! [maps]: crate::maps
-mod tc;
+mod cgroup_skb;
 mod kprobe;
 mod perf_attach;
 mod probe;
@@ -52,6 +52,7 @@ mod sk_msg;
 mod sk_skb;
 mod sock_ops;
 mod socket_filter;
+mod tc;
 mod trace_point;
 mod uprobe;
 mod xdp;
@@ -60,7 +61,7 @@ use libc::{close, dup, ENOSPC};
 use std::{cell::RefCell, cmp, convert::TryFrom, ffi::CStr, io, os::unix::io::RawFd, rc::Rc};
 use thiserror::Error;
 
-pub use tc::{SchedClassifier, TcError, TcAttachPoint};
+pub use cgroup_skb::{CgroupSkb, CgroupSkbAttachType};
 pub use kprobe::{KProbe, KProbeError};
 use perf_attach::*;
 pub use probe::ProbeKind;
@@ -68,6 +69,7 @@ pub use sk_msg::SkMsg;
 pub use sk_skb::{SkSkb, SkSkbKind};
 pub use sock_ops::SockOps;
 pub use socket_filter::{SocketFilter, SocketFilterError};
+pub use tc::{SchedClassifier, TcAttachPoint, TcError};
 pub use trace_point::{TracePoint, TracePointError};
 pub use uprobe::{UProbe, UProbeError};
 pub use xdp::{Xdp, XdpError, XdpFlags};
@@ -153,6 +155,7 @@ pub enum Program {
     SkSkb(SkSkb),
     SockOps(SockOps),
     SchedClassifier(SchedClassifier),
+    CgroupSkb(CgroupSkb),
 }
 
 impl Program {
@@ -183,6 +186,7 @@ impl Program {
             Program::SkSkb(_) => BPF_PROG_TYPE_SK_SKB,
             Program::SockOps(_) => BPF_PROG_TYPE_SOCK_OPS,
             Program::SchedClassifier(_) => BPF_PROG_TYPE_SCHED_CLS,
+            Program::CgroupSkb(_) => BPF_PROG_TYPE_CGROUP_SKB,
         }
     }
 
@@ -202,6 +206,7 @@ impl Program {
             Program::SkSkb(p) => &p.data,
             Program::SockOps(p) => &p.data,
             Program::SchedClassifier(p) => &p.data,
+            Program::CgroupSkb(p) => &p.data,
         }
     }
 
@@ -216,6 +221,7 @@ impl Program {
             Program::SkSkb(p) => &mut p.data,
             Program::SockOps(p) => &mut p.data,
             Program::SchedClassifier(p) => &mut p.data,
+            Program::CgroupSkb(p) => &mut p.data,
         }
     }
 }
@@ -496,5 +502,6 @@ impl_try_from_program!(
     SkMsg,
     SkSkb,
     SockOps,
-    SchedClassifier
+    SchedClassifier,
+    CgroupSkb
 );