Skip to content

Commit

Permalink
[216] Add Support For Flow Dissector Programs
Browse files Browse the repository at this point in the history
  • Loading branch information
azenna committed Oct 2, 2023
1 parent c547dd7 commit 1c58716
Show file tree
Hide file tree
Showing 14 changed files with 535 additions and 6 deletions.
66 changes: 66 additions & 0 deletions aya-bpf-macros/src/flow_dissector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use proc_macro2::TokenStream;
use proc_macro_error::abort;
use quote::quote;
use syn::{ItemFn, Result};

pub(crate) struct FlowDissector {
item: ItemFn,
}

impl FlowDissector {
pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
if !attrs.is_empty() {
abort!(attrs, "unexpected attribute")
}
let item = syn::parse2(item)?;
Ok(FlowDissector { item })
}

pub(crate) fn expand(&self) -> Result<TokenStream> {
let fn_name = self.item.sig.ident.clone();
let fn_vis = &self.item.vis;
let item = &self.item;
Ok(quote! {
#[no_mangle]
#[link_section = "flow_dissector"]
#fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> u32 {
return #fn_name(::aya_bpf::programs::FlowDissectorContext::new(ctx));

#item
}
})
}
}

#[cfg(test)]
mod tests {
use syn::parse_quote;

use super::*;

#[test]
fn test_flow_dissector() {
let prog = FlowDissector::parse(
parse_quote! {},
parse_quote! {
fn prog(ctx: &mut ::aya_bpf::programs::FlowDissectorContext) -> u32 {
0
}
},
)
.unwrap();
let expanded = prog.expand().unwrap();
let expected = quote! {
#[no_mangle]
#[link_section = "flow_dissector"]
fn prog(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> u32 {
return prog(::aya_bpf::programs::FlowDissectorContext::new(ctx));

fn prog(ctx: &mut ::aya_bpf::programs::FlowDissectorContext) -> u32 {
0
}
}
};
assert_eq!(expected.to_string(), expanded.to_string());
}
}
17 changes: 17 additions & 0 deletions aya-bpf-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod cgroup_sockopt;
mod cgroup_sysctl;
mod fentry;
mod fexit;
mod flow_dissector;
mod kprobe;
mod lsm;
mod map;
Expand All @@ -32,6 +33,7 @@ use cgroup_sockopt::CgroupSockopt;
use cgroup_sysctl::CgroupSysctl;
use fentry::FEntry;
use fexit::FExit;
use flow_dissector::FlowDissector;
use kprobe::{KProbe, KProbeKind};
use lsm::Lsm;
use map::Map;
Expand Down Expand Up @@ -605,6 +607,21 @@ pub fn fexit(attrs: TokenStream, item: TokenStream) -> TokenStream {
}
}

/// Marks a function as an eBPF Flow Dissector program that can be attached to
/// a network namespace.
///
#[proc_macro_error]
#[proc_macro_attribute]
pub fn flow_dissector(attrs: TokenStream, item: TokenStream) -> TokenStream {
match FlowDissector::parse(attrs.into(), item.into()) {
Ok(prog) => prog
.expand()
.unwrap_or_else(|err| abort!(err.span(), "{}", err))
.into(),
Err(err) => abort!(err.span(), "{}", err),
}
}

/// Marks a function as an eBPF Socket Lookup program that can be attached to
/// a network namespace.
///
Expand Down
2 changes: 2 additions & 0 deletions aya-obj/src/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ pub enum ProgramSection {
FExit {
sleepable: bool,
},
FlowDissector,
Extension,
SkLookup,
CgroupSock {
Expand Down Expand Up @@ -419,6 +420,7 @@ impl FromStr for ProgramSection {
"fentry.s" => FEntry { sleepable: true },
"fexit" => FExit { sleepable: false },
"fexit.s" => FExit { sleepable: true },
"flow_dissector" => FlowDissector,
"freplace" => Extension,
"sk_lookup" => SkLookup,
_ => {
Expand Down
11 changes: 8 additions & 3 deletions aya/src/bpf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ use crate::{
},
programs::{
BtfTracePoint, CgroupDevice, CgroupSkb, CgroupSkbAttachType, CgroupSock, CgroupSockAddr,
CgroupSockopt, CgroupSysctl, Extension, FEntry, FExit, KProbe, LircMode2, Lsm, PerfEvent,
ProbeKind, Program, ProgramData, ProgramError, RawTracePoint, SchedClassifier, SkLookup,
SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp,
CgroupSockopt, CgroupSysctl, Extension, FEntry, FExit, FlowDissector, KProbe, LircMode2,
Lsm, PerfEvent, ProbeKind, Program, ProgramData, ProgramError, RawTracePoint,
SchedClassifier, SkLookup, SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint,
UProbe, Xdp,
},
sys::{
bpf_load_btf, is_bpf_cookie_supported, is_bpf_global_data_supported,
Expand Down Expand Up @@ -434,6 +435,7 @@ impl<'a> BpfLoader<'a> {
| ProgramSection::PerfEvent
| ProgramSection::RawTracePoint
| ProgramSection::SkLookup
| ProgramSection::FlowDissector
| ProgramSection::CgroupSock { attach_type: _ }
| ProgramSection::CgroupDevice => {}
}
Expand Down Expand Up @@ -666,6 +668,9 @@ impl<'a> BpfLoader<'a> {
}
Program::FExit(FExit { data })
}
ProgramSection::FlowDissector => Program::FlowDissector(FlowDissector {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
}),
ProgramSection::Extension => Program::Extension(Extension {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
}),
Expand Down
109 changes: 109 additions & 0 deletions aya/src/programs/flow_dissector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//! Flow dissector programs.

use std::os::fd::AsFd;

use crate::{
generated::{bpf_attach_type::BPF_FLOW_DISSECTOR, bpf_prog_type::BPF_PROG_TYPE_FLOW_DISSECTOR},
programs::{define_link_wrapper, load_program, FdLink, FdLinkId, ProgramData, ProgramError},
sys::{bpf_link_create, LinkTarget, SyscallError},
};

/// A program that can be attached as a Flow Dissector routine
///
/// ['FlowDissector'] programs operate on an __sk_buff.
/// However, only the limited set of fields is allowed: data, data_end and flow_keys.
/// flow_keys is struct bpf_flow_keys and contains flow dissector input and output arguments.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 4.2.
///
/// # Examples
///
/// ```no_run
/// # #[derive(Debug, thiserror::Error)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::FlowDissector};
/// use std::fs::File;
///
/// let program: &mut FlowDissector = bpf.program_mut("filename_lookup").unwrap().try_into()?;
/// program.load()?;
///
/// let net_ns = File::open("/proc/self/ns/net")?;
/// program.attach(net_ns)?;
/// # Ok::<(), Error>(())
/// ```
#[derive(Debug)]
#[doc(alias = "BPF_PROG_TYPE_FLOW_DISSECTOR")]
pub struct FlowDissector {
pub(crate) data: ProgramData<FlowDissectorLink>,
}

impl FlowDissector {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(BPF_FLOW_DISSECTOR);
load_program(BPF_PROG_TYPE_FLOW_DISSECTOR, &mut self.data)
}

/// Attaches the program to the given network namespace.
///
/// The returned value can be used to detach, see [FlowDissector::detach].
pub fn attach<T: AsFd>(&mut self, netns: T) -> Result<FlowDissectorLinkId, ProgramError> {
let prog_fd = self.fd()?;
let prog_fd = prog_fd.as_fd();
let netns_fd = netns.as_fd();

let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(netns_fd),
BPF_FLOW_DISSECTOR,
None,
0,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
io_error,
})?;
self.data
.links
.insert(FlowDissectorLink::new(FdLink::new(link_fd)))
}

/// Detaches the program.
///
/// See [FlowDissector::attach].
pub fn detach(&mut self, link_id: FlowDissectorLinkId) -> Result<(), ProgramError> {
self.data.links.remove(link_id)
}

/// Takes ownership of the link referenced by the provided link_id.
///
/// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime.
pub fn take_link(
&mut self,
link_id: FlowDissectorLinkId,
) -> Result<FlowDissectorLink, ProgramError> {
self.data.take_link(link_id)
}
}

define_link_wrapper!(
/// The link used by [FlowDissector] programs.
FlowDissectorLink,
/// The type returned by [FlowDissector::attach]. Can be passed to [FlowDissector::detach].
FlowDissectorLinkId,
FdLink,
FdLinkId
);
15 changes: 15 additions & 0 deletions aya/src/programs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub mod cgroup_sysctl;
pub mod extension;
pub mod fentry;
pub mod fexit;
pub mod flow_dissector;
pub mod kprobe;
pub mod links;
pub mod lirc_mode2;
Expand Down Expand Up @@ -83,6 +84,7 @@ pub use cgroup_sysctl::CgroupSysctl;
pub use extension::{Extension, ExtensionError};
pub use fentry::FEntry;
pub use fexit::FExit;
pub use flow_dissector::FlowDissector;
pub use kprobe::{KProbe, KProbeError};
use libc::ENOSPC;
pub use links::Link;
Expand Down Expand Up @@ -276,6 +278,8 @@ pub enum Program {
FEntry(FEntry),
/// A [`FExit`] program
FExit(FExit),
/// A [`FlowDissector`] program
FlowDissector(FlowDissector),
/// A [`Extension`] program
Extension(Extension),
/// A [`SkLookup`] program
Expand Down Expand Up @@ -310,6 +314,7 @@ impl Program {
Self::BtfTracePoint(_) => BPF_PROG_TYPE_TRACING,
Self::FEntry(_) => BPF_PROG_TYPE_TRACING,
Self::FExit(_) => BPF_PROG_TYPE_TRACING,
Self::FlowDissector(_) => BPF_PROG_TYPE_FLOW_DISSECTOR,
Self::Extension(_) => BPF_PROG_TYPE_EXT,
Self::CgroupSockAddr(_) => BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
Self::SkLookup(_) => BPF_PROG_TYPE_SK_LOOKUP,
Expand Down Expand Up @@ -340,6 +345,7 @@ impl Program {
Self::BtfTracePoint(p) => p.pin(path),
Self::FEntry(p) => p.pin(path),
Self::FExit(p) => p.pin(path),
Self::FlowDissector(p) => p.pin(path),
Self::Extension(p) => p.pin(path),
Self::CgroupSockAddr(p) => p.pin(path),
Self::SkLookup(p) => p.pin(path),
Expand Down Expand Up @@ -370,6 +376,7 @@ impl Program {
Self::BtfTracePoint(mut p) => p.unload(),
Self::FEntry(mut p) => p.unload(),
Self::FExit(mut p) => p.unload(),
Self::FlowDissector(mut p) => p.unload(),
Self::Extension(mut p) => p.unload(),
Self::CgroupSockAddr(mut p) => p.unload(),
Self::SkLookup(mut p) => p.unload(),
Expand Down Expand Up @@ -402,6 +409,7 @@ impl Program {
Self::BtfTracePoint(p) => p.fd(),
Self::FEntry(p) => p.fd(),
Self::FExit(p) => p.fd(),
Self::FlowDissector(p) => p.fd(),
Self::Extension(p) => p.fd(),
Self::CgroupSockAddr(p) => p.fd(),
Self::SkLookup(p) => p.fd(),
Expand Down Expand Up @@ -435,6 +443,7 @@ impl Program {
Self::BtfTracePoint(p) => p.info(),
Self::FEntry(p) => p.info(),
Self::FExit(p) => p.info(),
Self::FlowDissector(p) => p.info(),
Self::Extension(p) => p.info(),
Self::CgroupSockAddr(p) => p.info(),
Self::SkLookup(p) => p.info(),
Expand Down Expand Up @@ -748,6 +757,7 @@ impl_program_unload!(
BtfTracePoint,
FEntry,
FExit,
FlowDissector,
Extension,
CgroupSockAddr,
SkLookup,
Expand Down Expand Up @@ -788,6 +798,7 @@ impl_fd!(
BtfTracePoint,
FEntry,
FExit,
FlowDissector,
Extension,
CgroupSockAddr,
SkLookup,
Expand Down Expand Up @@ -842,6 +853,7 @@ impl_program_pin!(
BtfTracePoint,
FEntry,
FExit,
FlowDissector,
Extension,
CgroupSockAddr,
SkLookup,
Expand Down Expand Up @@ -882,6 +894,7 @@ impl_from_pin!(
BtfTracePoint,
FEntry,
FExit,
FlowDissector,
Extension,
SkLookup,
SockOps,
Expand Down Expand Up @@ -936,6 +949,7 @@ impl_try_from_program!(
BtfTracePoint,
FEntry,
FExit,
FlowDissector,
Extension,
CgroupSockAddr,
SkLookup,
Expand Down Expand Up @@ -982,6 +996,7 @@ impl_info!(
BtfTracePoint,
FEntry,
FExit,
FlowDissector,
Extension,
CgroupSockAddr,
SkLookup,
Expand Down
Loading

0 comments on commit 1c58716

Please sign in to comment.