Skip to content

Commit

Permalink
feat(aya): Implement TCX
Browse files Browse the repository at this point in the history
This commit adds the initial support for TCX
bpf links. This is a new, multi-program, attachment
type allows for the caller to specify where
they would like to be attached relative to other
programs at the attachment point using the LinkOrder
type.

Signed-off-by: astoycos <[email protected]>
Co-authored-by: Andre Fredette <[email protected]>
Co-authored-by: Dave Tucker <[email protected]>
Co-authored-by: Tamir Duberstein <[email protected]>
  • Loading branch information
4 people committed Sep 28, 2024
1 parent 0f16363 commit d8f0595
Show file tree
Hide file tree
Showing 23 changed files with 915 additions and 131 deletions.
10 changes: 8 additions & 2 deletions aya/src/programs/cgroup_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
bpf_prog_get_fd_by_id, define_link_wrapper, load_program, query, CgroupAttachMode, FdLink,
Link, ProgAttachLink, ProgramData, ProgramError, ProgramFd,
},
sys::{bpf_link_create, LinkTarget, SyscallError},
sys::{bpf_link_create, LinkTarget, ProgQueryTarget, SyscallError},
util::KernelVersion,
};

Expand Down Expand Up @@ -77,6 +77,7 @@ impl CgroupDevice {
BPF_CGROUP_DEVICE,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
Expand Down Expand Up @@ -119,7 +120,12 @@ impl CgroupDevice {
/// Queries the cgroup for attached programs.
pub fn query<T: AsFd>(target_fd: T) -> Result<Vec<CgroupDeviceLink>, ProgramError> {
let target_fd = target_fd.as_fd();
let prog_ids = query(target_fd, BPF_CGROUP_DEVICE, 0, &mut None)?;
let (_, prog_ids) = query(
ProgQueryTarget::Fd(target_fd),
BPF_CGROUP_DEVICE,
0,
&mut None,
)?;

prog_ids
.into_iter()
Expand Down
1 change: 1 addition & 0 deletions aya/src/programs/cgroup_skb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ impl CgroupSkb {
attach_type,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
Expand Down
1 change: 1 addition & 0 deletions aya/src/programs/cgroup_sock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ impl CgroupSock {
attach_type,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
Expand Down
1 change: 1 addition & 0 deletions aya/src/programs/cgroup_sock_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl CgroupSockAddr {
attach_type,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
Expand Down
1 change: 1 addition & 0 deletions aya/src/programs/cgroup_sockopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ impl CgroupSockopt {
attach_type,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
Expand Down
1 change: 1 addition & 0 deletions aya/src/programs/cgroup_sysctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ impl CgroupSysctl {
BPF_CGROUP_SYSCTL,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
Expand Down
2 changes: 2 additions & 0 deletions aya/src/programs/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ impl Extension {
BPF_CGROUP_INET_INGRESS,
Some(btf_id),
0,
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
Expand Down Expand Up @@ -140,6 +141,7 @@ impl Extension {
BPF_CGROUP_INET_INGRESS,
Some(btf_id),
0,
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
Expand Down
130 changes: 126 additions & 4 deletions aya/src/programs/links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ use std::{
use thiserror::Error;

use crate::{
generated::{bpf_attach_type, BPF_F_ALLOW_MULTI, BPF_F_ALLOW_OVERRIDE},
generated::{
bpf_attach_type, BPF_F_AFTER, BPF_F_ALLOW_MULTI, BPF_F_ALLOW_OVERRIDE, BPF_F_BEFORE,
BPF_F_ID, BPF_F_LINK, BPF_F_REPLACE,
},
pin::PinError,
programs::{ProgramError, ProgramFd},
programs::{MultiProgLink, MultiProgram, ProgramError, ProgramFd, ProgramId},
sys::{bpf_get_object, bpf_pin_object, bpf_prog_attach, bpf_prog_detach, SyscallError},
};

Expand Down Expand Up @@ -116,7 +119,7 @@ pub struct FdLinkId(pub(crate) RawFd);
///
/// # Example
///
///```no_run
/// ```no_run
/// # let mut bpf = Ebpf::load_file("ebpf_programs.o")?;
/// use aya::{Ebpf, programs::{links::FdLink, KProbe}};
///
Expand Down Expand Up @@ -329,7 +332,7 @@ macro_rules! define_link_wrapper {
pub struct $wrapper(Option<$base>);

#[allow(dead_code)]
// allow dead code since currently XDP is the only consumer of inner and
// allow dead code since currently XDP/TC are the only consumers of inner and
// into_inner
impl $wrapper {
fn new(base: $base) -> $wrapper {
Expand Down Expand Up @@ -394,6 +397,125 @@ pub enum LinkError {
SyscallError(#[from] SyscallError),
}

#[derive(Debug)]
pub(crate) enum LinkRef {
Id(u32),
Fd(RawFd),
}

bitflags::bitflags! {
/// Flags which are use to build a set of MprogOptions.
#[derive(Clone, Copy, Debug, Default)]
pub(crate) struct MprogFlags: u32 {
const REPLACE = BPF_F_REPLACE;
const BEFORE = BPF_F_BEFORE;
const AFTER = BPF_F_AFTER;
const ID = BPF_F_ID;
const LINK = BPF_F_LINK;
}
}

/// Arguments required for interacting with the kernel's multi-prog API.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 6.6.0.
///
/// # Example
///
/// ```no_run
/// # let mut bpf = aya::Ebpf::load(&[])?;
/// use aya::programs::{tc, SchedClassifier, TcAttachType, tc::TcAttachOptions, LinkOrder};
///
/// let prog: &mut SchedClassifier = bpf.program_mut("redirect_ingress").unwrap().try_into()?;
/// prog.load()?;
/// let options = TcAttachOptions::TcxOrder(LinkOrder::first());
/// prog.attach_with_options("eth0", TcAttachType::Ingress, options)?;
///
/// # Ok::<(), aya::EbpfError>(())
/// ```
#[derive(Debug)]
pub struct LinkOrder {
pub(crate) link_ref: LinkRef,
pub(crate) flags: MprogFlags,
}

/// Ensure that default link ordering is to be attached last.
impl Default for LinkOrder {
fn default() -> Self {
Self {
link_ref: LinkRef::Fd(0),
flags: MprogFlags::AFTER,
}
}
}

impl LinkOrder {
/// Attach before all other links.
pub fn first() -> Self {
Self {
link_ref: LinkRef::Id(0),
flags: MprogFlags::BEFORE,
}
}

/// Attach after all other links.
pub fn last() -> Self {
Self {
link_ref: LinkRef::Id(0),
flags: MprogFlags::AFTER,
}
}

/// Attach before the given link.
pub fn before_link<L: MultiProgLink>(link: &L) -> Result<Self, LinkError> {
Ok(Self {
link_ref: LinkRef::Fd(link.fd()?.as_raw_fd()),
flags: MprogFlags::BEFORE | MprogFlags::LINK,
})
}

/// Attach after the given link.
pub fn after_link<L: MultiProgLink>(link: &L) -> Result<Self, LinkError> {
Ok(Self {
link_ref: LinkRef::Fd(link.fd()?.as_raw_fd()),
flags: MprogFlags::AFTER | MprogFlags::LINK,
})
}

/// Attach before the given program.
pub fn before_program<P: MultiProgram>(program: &P) -> Result<Self, ProgramError> {
Ok(Self {
link_ref: LinkRef::Fd(program.fd()?.as_raw_fd()),
flags: MprogFlags::BEFORE,
})
}

/// Attach after the given program.
pub fn after_program<P: MultiProgram>(program: &P) -> Result<Self, ProgramError> {
Ok(Self {
link_ref: LinkRef::Fd(program.fd()?.as_raw_fd()),
flags: MprogFlags::AFTER,
})
}

/// Attach before the program with the given id.
pub fn before_program_id(id: ProgramId) -> Self {
Self {
link_ref: LinkRef::Id(id.0),
flags: MprogFlags::BEFORE | MprogFlags::ID,
}
}

/// Attach after the program with the given id.
pub fn after_program_id(id: ProgramId) -> Self {
Self {
link_ref: LinkRef::Id(id.0),
flags: MprogFlags::AFTER | MprogFlags::ID,
}
}
}

#[cfg(test)]
mod tests {
use std::{cell::RefCell, fs::File, rc::Rc};
Expand Down
4 changes: 2 additions & 2 deletions aya/src/programs/lirc_mode2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
load_program, query, CgroupAttachMode, Link, ProgramData, ProgramError, ProgramFd,
ProgramInfo,
},
sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id},
sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, ProgQueryTarget},
};

/// A program used to decode IR into key events for a lirc device.
Expand Down Expand Up @@ -100,7 +100,7 @@ impl LircMode2 {
/// Queries the lirc device for attached programs.
pub fn query<T: AsFd>(target_fd: T) -> Result<Vec<LircLink>, ProgramError> {
let target_fd = target_fd.as_fd();
let prog_ids = query(target_fd, BPF_LIRC_MODE2, 0, &mut None)?;
let (_, prog_ids) = query(ProgQueryTarget::Fd(target_fd), BPF_LIRC_MODE2, 0, &mut None)?;

prog_ids
.into_iter()
Expand Down
Loading

0 comments on commit d8f0595

Please sign in to comment.