feat(aya): Implement TCX

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 <astoycos@redhat.com>
Co-authored-by: Andre Fredette <afredette@redhat.com>
Co-authored-by: Dave Tucker <dave@dtucker.co.uk>
Co-authored-by: Tamir Duberstein <tamird@gmail.com>
pull/1051/head
astoycos 10 months ago committed by Alessandro Decina
parent 1d272f38bd
commit 5478cac008

@ -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,
};
@ -77,6 +77,7 @@ impl CgroupDevice {
BPF_CGROUP_DEVICE,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
@ -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()

@ -105,6 +105,7 @@ impl CgroupSkb {
attach_type,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",

@ -83,6 +83,7 @@ impl CgroupSock {
attach_type,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",

@ -84,6 +84,7 @@ impl CgroupSockAddr {
attach_type,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",

@ -81,6 +81,7 @@ impl CgroupSockopt {
attach_type,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",

@ -76,6 +76,7 @@ impl CgroupSysctl {
BPF_CGROUP_SYSCTL,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",

@ -103,6 +103,7 @@ impl Extension {
BPF_CGROUP_INET_INGRESS,
Some(btf_id),
0,
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
@ -140,6 +141,7 @@ impl Extension {
BPF_CGROUP_INET_INGRESS,
Some(btf_id),
0,
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",

@ -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},
};
@ -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 {
@ -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};

@ -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.
@ -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()

@ -72,7 +72,7 @@ pub mod xdp;
use std::{
ffi::CString,
io,
os::fd::{AsFd, AsRawFd, BorrowedFd},
os::fd::{AsFd, BorrowedFd},
path::{Path, PathBuf},
sync::Arc,
};
@ -80,6 +80,7 @@ use std::{
use info::impl_info;
pub use info::{loaded_programs, ProgramInfo, ProgramType};
use libc::ENOSPC;
use tc::SchedClassifierLink;
use thiserror::Error;
// re-export the main items needed to load and attach
@ -94,7 +95,7 @@ pub use crate::programs::{
fentry::FEntry,
fexit::FExit,
kprobe::{KProbe, KProbeError},
links::{CgroupAttachMode, Link},
links::{CgroupAttachMode, Link, LinkOrder},
lirc_mode2::LircMode2,
lsm::Lsm,
perf_event::{PerfEvent, PerfEventScope, PerfTypeId, SamplePolicy},
@ -120,7 +121,7 @@ use crate::{
sys::{
bpf_btf_get_fd_by_id, bpf_get_object, bpf_link_get_fd_by_id, bpf_link_get_info_by_fd,
bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_query, iter_link_ids,
retry_with_verifier_logs, EbpfLoadProgramAttrs, SyscallError,
retry_with_verifier_logs, EbpfLoadProgramAttrs, ProgQueryTarget, SyscallError,
},
util::KernelVersion,
VerifierLogLevel,
@ -238,7 +239,20 @@ impl AsFd for ProgramFd {
}
}
/// The various eBPF programs.
/// A [`Program`] identifier.
pub struct ProgramId(u32);
impl ProgramId {
/// Create a new program id.
///
/// This method is unsafe since it doesn't check that the given `id` is a
/// valid program id.
pub unsafe fn new(id: u32) -> Self {
Self(id)
}
}
/// eBPF program type.
#[derive(Debug)]
pub enum Program {
/// A [`KProbe`] program
@ -668,28 +682,30 @@ fn load_program<T: Link>(
}
pub(crate) fn query(
target_fd: BorrowedFd<'_>,
target: ProgQueryTarget<'_>,
attach_type: bpf_attach_type,
query_flags: u32,
attach_flags: &mut Option<u32>,
) -> Result<Vec<u32>, ProgramError> {
) -> Result<(u64, Vec<u32>), ProgramError> {
let mut prog_ids = vec![0u32; 64];
let mut prog_cnt = prog_ids.len() as u32;
let mut revision = 0;
let mut retries = 0;
loop {
match bpf_prog_query(
target_fd.as_fd().as_raw_fd(),
&target,
attach_type,
query_flags,
attach_flags.as_mut(),
&mut prog_ids,
&mut prog_cnt,
&mut revision,
) {
Ok(_) => {
prog_ids.resize(prog_cnt as usize, 0);
return Ok(prog_ids);
return Ok((revision, prog_ids));
}
Err((_, io_error)) => {
if retries == 0 && io_error.raw_os_error() == Some(ENOSPC) {
@ -797,6 +813,57 @@ impl_fd!(
CgroupDevice,
);
/// Trait implemented by the [`Program`] types which support the kernel's
/// [generic multi-prog API](https://github.com/torvalds/linux/commit/053c8e1f235dc3f69d13375b32f4209228e1cb96).
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 6.6.0.
pub trait MultiProgram {
/// Borrows the file descriptor.
fn fd(&self) -> Result<BorrowedFd<'_>, ProgramError>;
}
macro_rules! impl_multiprog_fd {
($($struct_name:ident),+ $(,)?) => {
$(
impl MultiProgram for $struct_name {
fn fd(&self) -> Result<BorrowedFd<'_>, ProgramError> {
Ok(self.fd()?.as_fd())
}
}
)+
}
}
impl_multiprog_fd!(SchedClassifier);
/// Trait implemented by the [`Link`] types which support the kernel's
/// [generic multi-prog API](https://github.com/torvalds/linux/commit/053c8e1f235dc3f69d13375b32f4209228e1cb96).
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 6.6.0.
pub trait MultiProgLink {
/// Borrows the file descriptor.
fn fd(&self) -> Result<BorrowedFd<'_>, LinkError>;
}
macro_rules! impl_multiproglink_fd {
($($struct_name:ident),+ $(,)?) => {
$(
impl MultiProgLink for $struct_name {
fn fd(&self) -> Result<BorrowedFd<'_>, LinkError> {
let link: &FdLink = self.try_into()?;
Ok(link.fd.as_fd())
}
}
)+
}
}
impl_multiproglink_fd!(SchedClassifierLink);
macro_rules! impl_program_pin{
($($struct_name:ident),+ $(,)?) => {
$(

@ -75,7 +75,14 @@ pub(crate) fn perf_attach(
fd: crate::MockableFd,
) -> Result<PerfLinkInner, ProgramError> {
if FEATURES.bpf_perf_link() {
let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(fd.as_fd()), BPF_PERF_EVENT, None, 0)
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(fd.as_fd()),
BPF_PERF_EVENT,
None,
0,
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
io_error,

@ -65,7 +65,14 @@ impl SkLookup {
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_SK_LOOKUP, None, 0)
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(netns_fd),
BPF_SK_LOOKUP,
None,
0,
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",
io_error,

@ -75,6 +75,7 @@ impl SockOps {
attach_type,
None,
mode.into(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",

@ -8,16 +8,24 @@ use std::{
use thiserror::Error;
use super::{FdLink, ProgramInfo};
use crate::{
generated::{
bpf_prog_type::BPF_PROG_TYPE_SCHED_CLS, TC_H_CLSACT, TC_H_MIN_EGRESS, TC_H_MIN_INGRESS,
bpf_attach_type::{self, BPF_TCX_EGRESS, BPF_TCX_INGRESS},
bpf_link_type,
bpf_prog_type::BPF_PROG_TYPE_SCHED_CLS,
TC_H_CLSACT, TC_H_MIN_EGRESS, TC_H_MIN_INGRESS,
},
programs::{
define_link_wrapper, load_program, query, Link, LinkError, LinkOrder, ProgramData,
ProgramError,
},
programs::{define_link_wrapper, load_program, Link, ProgramData, ProgramError},
sys::{
bpf_link_create, bpf_link_get_info_by_fd, bpf_link_update, bpf_prog_get_fd_by_id,
netlink_find_filter_with_name, netlink_qdisc_add_clsact, netlink_qdisc_attach,
netlink_qdisc_detach,
netlink_qdisc_detach, LinkTarget, ProgQueryTarget, SyscallError,
},
util::{ifindex_from_ifname, tc_handler_make},
util::{ifindex_from_ifname, tc_handler_make, KernelVersion},
VerifierLogLevel,
};
@ -89,21 +97,49 @@ pub enum TcError {
/// the clsact qdisc is already attached
#[error("the clsact qdisc is already attached")]
AlreadyAttached,
/// tcx links can only be attached to ingress or egress, custom attachment is not supported
#[error("tcx links can only be attached to ingress or egress, custom attachment: {0} is not supported")]
InvalidTcxAttach(u32),
/// operation not supported for programs loaded via tcx
#[error("operation not supported for programs loaded via tcx")]
InvalidLinkOperation,
}
impl TcAttachType {
pub(crate) fn parent(&self) -> u32 {
pub(crate) fn tc_parent(&self) -> u32 {
match self {
Self::Custom(parent) => *parent,
Self::Ingress => tc_handler_make(TC_H_CLSACT, TC_H_MIN_INGRESS),
Self::Egress => tc_handler_make(TC_H_CLSACT, TC_H_MIN_EGRESS),
}
}
pub(crate) fn tcx_attach_type(&self) -> Result<bpf_attach_type, TcError> {
match self {
Self::Ingress => Ok(BPF_TCX_INGRESS),
Self::Egress => Ok(BPF_TCX_EGRESS),
Self::Custom(tcx_attach_type) => Err(TcError::InvalidTcxAttach(*tcx_attach_type)),
}
}
}
/// Options for a SchedClassifier attach operation.
///
/// The options vary based on what is supported by the current kernel. Kernels
/// older than 6.6.0 must utilize netlink for attachments, while newer kernels
/// can utilize the modern TCX eBPF link type which supports the kernel's
/// multi-prog API.
#[derive(Debug)]
pub enum TcAttachOptions {
/// Netlink attach options.
Netlink(NlOptions),
/// Tcx attach options.
TcxOrder(LinkOrder),
}
/// Options for SchedClassifier attach
#[derive(Default)]
pub struct TcOptions {
/// Options for SchedClassifier attach via netlink.
#[derive(Debug, Default, Hash, Eq, PartialEq)]
pub struct NlOptions {
/// Priority assigned to tc program with lower number = higher priority.
/// If set to default (0), the system chooses the next highest priority or 49152 if no filters exist yet
pub priority: u16,
@ -118,25 +154,46 @@ impl SchedClassifier {
load_program(BPF_PROG_TYPE_SCHED_CLS, &mut self.data)
}
/// Attaches the program to the given `interface` using the default options.
/// Attaches the program to the given `interface`.
///
/// On kernels >= 6.6.0, it will attempt to use the TCX interface and attach as
/// the last TCX program. On older kernels, it will fallback to using the
/// legacy netlink interface.
///
/// For finer grained control over link ordering use [`SchedClassifier::attach_with_options`].
///
/// The returned value can be used to detach, see [SchedClassifier::detach].
///
/// # Errors
///
/// [`TcError::NetlinkError`] is returned if attaching fails. A common cause
/// of failure is not having added the `clsact` qdisc to the given
/// interface, see [`qdisc_add_clsact`]
/// When attaching fails, [`ProgramError::SyscallError`] is returned for
/// kernels `>= 6.6.0`, and [`TcError::NetlinkError`] is returned for
/// older kernels. A common cause of netlink attachment failure is not having added
/// the `clsact` qdisc to the given interface, see [`qdisc_add_clsact`]
///
pub fn attach(
&mut self,
interface: &str,
attach_type: TcAttachType,
) -> Result<SchedClassifierLinkId, ProgramError> {
self.attach_with_options(interface, attach_type, TcOptions::default())
if !matches!(attach_type, TcAttachType::Custom(_))
&& KernelVersion::current().unwrap() >= KernelVersion::new(6, 6, 0)
{
self.attach_with_options(
interface,
attach_type,
TcAttachOptions::TcxOrder(LinkOrder::default()),
)
} else {
self.attach_with_options(
interface,
attach_type,
TcAttachOptions::Netlink(NlOptions::default()),
)
}
}
/// Attaches the program to the given `interface` with options defined in [`TcOptions`].
/// Attaches the program to the given `interface` with options defined in [`TcAttachOptions`].
///
/// The returned value can be used to detach, see [SchedClassifier::detach].
///
@ -150,11 +207,11 @@ impl SchedClassifier {
&mut self,
interface: &str,
attach_type: TcAttachType,
options: TcOptions,
options: TcAttachOptions,
) -> Result<SchedClassifierLinkId, ProgramError> {
let if_index = ifindex_from_ifname(interface)
.map_err(|io_error| TcError::NetlinkError { io_error })?;
self.do_attach(if_index as i32, attach_type, options, true)
self.do_attach(if_index, attach_type, options, true)
}
/// Atomically replaces the program referenced by the provided link.
@ -164,30 +221,58 @@ impl SchedClassifier {
&mut self,
link: SchedClassifierLink,
) -> Result<SchedClassifierLinkId, ProgramError> {
let TcLink {
let prog_fd = self.fd()?;
let prog_fd = prog_fd.as_fd();
match link.into_inner() {
TcLinkInner::FdLink(link) => {
let fd = link.fd;
let link_fd = fd.as_fd();
bpf_link_update(link_fd.as_fd(), prog_fd, None, 0).map_err(|(_, io_error)| {
SyscallError {
call: "bpf_link_update",
io_error,
}
})?;
self.data
.links
.insert(SchedClassifierLink::new(TcLinkInner::FdLink(FdLink::new(
fd,
))))
}
TcLinkInner::NlLink(NlLink {
if_index,
attach_type,
priority,
handle,
} = link.into_inner();
self.do_attach(if_index, attach_type, TcOptions { priority, handle }, false)
}) => self.do_attach(
if_index,
attach_type,
TcAttachOptions::Netlink(NlOptions { priority, handle }),
false,
),
}
}
fn do_attach(
&mut self,
if_index: i32,
if_index: u32,
attach_type: TcAttachType,
options: TcOptions,
options: TcAttachOptions,
create: bool,
) -> Result<SchedClassifierLinkId, ProgramError> {
let prog_fd = self.fd()?;
let prog_fd = prog_fd.as_fd();
match options {
TcAttachOptions::Netlink(options) => {
let name = self.data.name.as_deref().unwrap_or_default();
// TODO: avoid this unwrap by adding a new error variant.
let name = CString::new(name).unwrap();
let (priority, handle) = unsafe {
netlink_qdisc_attach(
if_index,
if_index as i32,
&attach_type,
prog_fd,
&name,
@ -198,12 +283,36 @@ impl SchedClassifier {
}
.map_err(|io_error| TcError::NetlinkError { io_error })?;
self.data.links.insert(SchedClassifierLink::new(TcLink {
self.data
.links
.insert(SchedClassifierLink::new(TcLinkInner::NlLink(NlLink {
if_index,
attach_type,
priority,
handle,
}))
})))
}
TcAttachOptions::TcxOrder(options) => {
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::IfIndex(if_index),
attach_type.tcx_attach_type()?,
None,
options.flags.bits(),
Some(&options.link_ref),
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_mprog_attach",
io_error,
})?;
self.data
.links
.insert(SchedClassifierLink::new(TcLinkInner::FdLink(FdLink::new(
link_fd,
))))
}
}
}
/// Detaches the program.
@ -234,42 +343,153 @@ impl SchedClassifier {
let data = ProgramData::from_pinned_path(path, VerifierLogLevel::default())?;
Ok(Self { data })
}
/// Queries a given interface for attached TCX programs.
///
/// # Example
///
/// ```no_run
/// # use aya::programs::tc::{TcAttachType, SchedClassifier};
/// # #[derive(Debug, thiserror::Error)]
/// # enum Error {
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # }
/// let (revision, programs) = SchedClassifier::query_tcx("eth0", TcAttachType::Ingress)?;
/// # Ok::<(), Error>(())
/// ```
pub fn query_tcx(
interface: &str,
attach_type: TcAttachType,
) -> Result<(u64, Vec<ProgramInfo>), ProgramError> {
let if_index = ifindex_from_ifname(interface)
.map_err(|io_error| TcError::NetlinkError { io_error })?;
let (revision, prog_ids) = query(
ProgQueryTarget::IfIndex(if_index),
attach_type.tcx_attach_type()?,
0,
&mut None,
)?;
let prog_infos = prog_ids
.into_iter()
.map(|prog_id| {
let prog_fd = bpf_prog_get_fd_by_id(prog_id)?;
let prog_info = ProgramInfo::new_from_fd(prog_fd.as_fd())?;
Ok::<ProgramInfo, ProgramError>(prog_info)
})
.collect::<Result<_, _>>()?;
Ok((revision, prog_infos))
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
pub(crate) struct TcLinkId(i32, TcAttachType, u16, u32);
pub(crate) struct NlLinkId(u32, TcAttachType, u16, u32);
#[derive(Debug)]
struct TcLink {
if_index: i32,
pub(crate) struct NlLink {
if_index: u32,
attach_type: TcAttachType,
priority: u16,
handle: u32,
}
impl Link for TcLink {
type Id = TcLinkId;
impl Link for NlLink {
type Id = NlLinkId;
fn id(&self) -> Self::Id {
TcLinkId(self.if_index, self.attach_type, self.priority, self.handle)
NlLinkId(self.if_index, self.attach_type, self.priority, self.handle)
}
fn detach(self) -> Result<(), ProgramError> {
unsafe {
netlink_qdisc_detach(self.if_index, &self.attach_type, self.priority, self.handle)
netlink_qdisc_detach(
self.if_index as i32,
&self.attach_type,
self.priority,
self.handle,
)
}
.map_err(|io_error| TcError::NetlinkError { io_error })?;
Ok(())
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
pub(crate) enum TcLinkIdInner {
FdLinkId(<FdLink as Link>::Id),
NlLinkId(<NlLink as Link>::Id),
}
#[derive(Debug)]
pub(crate) enum TcLinkInner {
FdLink(FdLink),
NlLink(NlLink),
}
impl Link for TcLinkInner {
type Id = TcLinkIdInner;
fn id(&self) -> Self::Id {
match self {
Self::FdLink(link) => TcLinkIdInner::FdLinkId(link.id()),
Self::NlLink(link) => TcLinkIdInner::NlLinkId(link.id()),
}
}
fn detach(self) -> Result<(), ProgramError> {
match self {
Self::FdLink(link) => link.detach(),
Self::NlLink(link) => link.detach(),
}
}
}
impl<'a> TryFrom<&'a SchedClassifierLink> for &'a FdLink {
type Error = LinkError;
fn try_from(value: &'a SchedClassifierLink) -> Result<Self, Self::Error> {
if let TcLinkInner::FdLink(fd) = value.inner() {
Ok(fd)
} else {
Err(LinkError::InvalidLink)
}
}
}
impl TryFrom<SchedClassifierLink> for FdLink {
type Error = LinkError;
fn try_from(value: SchedClassifierLink) -> Result<Self, Self::Error> {
if let TcLinkInner::FdLink(fd) = value.into_inner() {
Ok(fd)
} else {
Err(LinkError::InvalidLink)
}
}
}
impl TryFrom<FdLink> for SchedClassifierLink {
type Error = LinkError;
fn try_from(fd_link: FdLink) -> Result<Self, Self::Error> {
let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?;
if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TCX as u32) {
return Ok(Self::new(TcLinkInner::FdLink(fd_link)));
}
Err(LinkError::InvalidLink)
}
}
define_link_wrapper!(
/// The link used by [SchedClassifier] programs.
SchedClassifierLink,
/// The type returned by [SchedClassifier::attach]. Can be passed to [SchedClassifier::detach].
SchedClassifierLinkId,
TcLink,
TcLinkId
TcLinkInner,
TcLinkIdInner
);
impl SchedClassifierLink {
@ -311,27 +531,39 @@ impl SchedClassifierLink {
handle: u32,
) -> Result<Self, io::Error> {
let if_index = ifindex_from_ifname(if_name)?;
Ok(Self(Some(TcLink {
if_index: if_index as i32,
Ok(Self(Some(TcLinkInner::NlLink(NlLink {
if_index,
attach_type,
priority,
handle,
})))
}))))
}
/// Returns the attach type.
pub fn attach_type(&self) -> TcAttachType {
self.inner().attach_type
pub fn attach_type(&self) -> Result<TcAttachType, ProgramError> {
if let TcLinkInner::NlLink(n) = self.inner() {
Ok(n.attach_type)
} else {
Err(TcError::InvalidLinkOperation.into())
}
}
/// Returns the allocated priority. If none was provided at attach time, this was allocated for you.
pub fn priority(&self) -> u16 {
self.inner().priority
pub fn priority(&self) -> Result<u16, ProgramError> {
if let TcLinkInner::NlLink(n) = self.inner() {
Ok(n.priority)
} else {
Err(TcError::InvalidLinkOperation.into())
}
}
/// Returns the assigned handle. If none was provided at attach time, this was allocated for you.
pub fn handle(&self) -> u32 {
self.inner().handle
pub fn handle(&self) -> Result<u32, ProgramError> {
if let TcLinkInner::NlLink(n) = self.inner() {
Ok(n.handle)
} else {
Err(TcError::InvalidLinkOperation.into())
}
}
}

@ -140,7 +140,7 @@ impl Xdp {
// if the program has been loaded, i.e. there is an fd. We get one by:
// - Using `Xdp::from_pin` that sets `expected_attach_type`
// - Calling `Xdp::attach` that sets `expected_attach_type`, as geting an `Xdp`
// instance trhough `Xdp:try_from(Program)` does not set any fd.
// instance through `Xdp:try_from(Program)` does not set any fd.
// So, in all cases where we have an fd, we have an expected_attach_type. Thus, if we
// reach this point, expected_attach_type is guaranteed to be Some(_).
let attach_type = self.data.expected_attach_type.unwrap();
@ -150,6 +150,7 @@ impl Xdp {
attach_type,
None,
flags.bits(),
None,
)
.map_err(|(_, io_error)| SyscallError {
call: "bpf_link_create",

@ -30,6 +30,7 @@ use crate::{
},
copy_instructions,
},
programs::links::LinkRef,
sys::{syscall, SysResult, Syscall, SyscallError},
util::KernelVersion,
Btf, Pod, VerifierLogLevel, BPF_OBJ_NAME_LEN, FEATURES,
@ -385,6 +386,7 @@ pub(crate) fn bpf_link_create(
attach_type: bpf_attach_type,
btf_id: Option<u32>,
flags: u32,
link_ref: Option<&LinkRef>,
) -> SysResult<crate::MockableFd> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
@ -399,11 +401,32 @@ pub(crate) fn bpf_link_create(
}
};
attr.link_create.attach_type = attach_type as u32;
attr.link_create.flags = flags;
if let Some(btf_id) = btf_id {
attr.link_create.__bindgen_anon_3.target_btf_id = btf_id;
}
attr.link_create.flags = flags;
// since kernel 6.6
match link_ref {
Some(LinkRef::Fd(fd)) => {
attr.link_create
.__bindgen_anon_3
.tcx
.__bindgen_anon_1
.relative_fd = fd.to_owned() as u32;
}
Some(LinkRef::Id(id)) => {
attr.link_create
.__bindgen_anon_3
.tcx
.__bindgen_anon_1
.relative_id = id.to_owned();
}
None => {}
};
// SAFETY: BPF_LINK_CREATE returns a new file descriptor.
unsafe { fd_sys_bpf(bpf_cmd::BPF_LINK_CREATE, &mut attr) }
}
@ -475,25 +498,39 @@ pub(crate) fn bpf_prog_detach(
Ok(())
}
#[derive(Debug)]
pub(crate) enum ProgQueryTarget<'a> {
Fd(BorrowedFd<'a>),
IfIndex(u32),
}
pub(crate) fn bpf_prog_query(
target_fd: RawFd,
target: &ProgQueryTarget<'_>,
attach_type: bpf_attach_type,
query_flags: u32,
attach_flags: Option<&mut u32>,
prog_ids: &mut [u32],
prog_cnt: &mut u32,
revision: &mut u64,
) -> SysResult<i64> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
attr.query.__bindgen_anon_1.target_fd = target_fd as u32;
match target {
ProgQueryTarget::Fd(fd) => {
attr.query.__bindgen_anon_1.target_fd = fd.as_raw_fd() as u32;
}
ProgQueryTarget::IfIndex(ifindex) => {
attr.query.__bindgen_anon_1.target_ifindex = *ifindex;
}
}
attr.query.attach_type = attach_type as u32;
attr.query.query_flags = query_flags;
attr.query.__bindgen_anon_2.prog_cnt = prog_ids.len() as u32;
attr.query.prog_ids = prog_ids.as_mut_ptr() as u64;
let ret = sys_bpf(bpf_cmd::BPF_PROG_QUERY, &mut attr);
*prog_cnt = unsafe { attr.query.__bindgen_anon_2.prog_cnt };
*revision = unsafe { attr.query.revision };
if let Some(attach_flags) = attach_flags {
*attach_flags = unsafe { attr.query.attach_flags };
@ -826,7 +863,7 @@ pub(crate) fn is_perf_link_supported() -> bool {
let fd = fd.as_fd();
matches!(
// Uses an invalid target FD so we get EBADF if supported.
bpf_link_create(fd, LinkTarget::IfIndex(u32::MAX), bpf_attach_type::BPF_PERF_EVENT, None, 0),
bpf_link_create(fd, LinkTarget::IfIndex(u32::MAX), bpf_attach_type::BPF_PERF_EVENT, None, 0, None),
// Returns EINVAL if unsupported. EBADF if supported.
Err((_, e)) if e.raw_os_error() == Some(libc::EBADF),
)

@ -146,7 +146,7 @@ pub(crate) unsafe fn netlink_qdisc_attach(
req.tc_info.tcm_family = AF_UNSPEC as u8;
req.tc_info.tcm_handle = handle; // auto-assigned, if zero
req.tc_info.tcm_ifindex = if_index;
req.tc_info.tcm_parent = attach_type.parent();
req.tc_info.tcm_parent = attach_type.tc_parent();
req.tc_info.tcm_info = tc_handler_make((priority as u32) << 16, htons(ETH_P_ALL as u16) as u32);
let attrs_buf = request_attributes(&mut req, nlmsg_len);
@ -207,7 +207,7 @@ pub(crate) unsafe fn netlink_qdisc_detach(
req.tc_info.tcm_family = AF_UNSPEC as u8;
req.tc_info.tcm_handle = handle; // auto-assigned, if zero
req.tc_info.tcm_info = tc_handler_make((priority as u32) << 16, htons(ETH_P_ALL as u16) as u32);
req.tc_info.tcm_parent = attach_type.parent();
req.tc_info.tcm_parent = attach_type.tc_parent();
req.tc_info.tcm_ifindex = if_index;
sock.send(&bytes_of(&req)[..req.header.nlmsg_len as usize])?;
@ -236,7 +236,7 @@ pub(crate) unsafe fn netlink_find_filter_with_name(
req.tc_info.tcm_family = AF_UNSPEC as u8;
req.tc_info.tcm_handle = 0; // auto-assigned, if zero
req.tc_info.tcm_ifindex = if_index;
req.tc_info.tcm_parent = attach_type.parent();
req.tc_info.tcm_parent = attach_type.tc_parent();
let sock = NetlinkSocket::open()?;
sock.send(&bytes_of(&req)[..req.header.nlmsg_len as usize])?;

@ -37,6 +37,10 @@ path = "src/pass.rs"
name = "test"
path = "src/test.rs"
[[bin]]
name = "tcx"
path = "src/tcx.rs"
[[bin]]
name = "relocations"
path = "src/relocations.rs"

@ -0,0 +1,15 @@
#![no_std]
#![no_main]
use aya_ebpf::{bindings::tcx_action_base::TCX_NEXT, macros::classifier, programs::TcContext};
#[classifier]
pub fn tcx_next(_ctx: TcContext) -> i32 {
TCX_NEXT
}
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}

@ -14,6 +14,7 @@ pub const LOG: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/log"));
pub const MAP_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/map_test"));
pub const NAME_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/name_test"));
pub const PASS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/pass"));
pub const TCX: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/tcx"));
pub const TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/test"));
pub const RELOCATIONS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/relocations"));
pub const TWO_PROGS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/two_progs"));

@ -8,4 +8,5 @@ mod rbpf;
mod relocations;
mod ring_buf;
mod smoke;
mod tcx;
mod xdp;

@ -0,0 +1,102 @@
use aya::{
programs::{tc::TcAttachOptions, LinkOrder, ProgramId, SchedClassifier, TcAttachType},
util::KernelVersion,
Ebpf,
};
use test_log::test;
use crate::utils::NetNsGuard;
#[test]
fn tcx() {
let kernel_version = KernelVersion::current().unwrap();
if kernel_version < KernelVersion::new(6, 6, 0) {
eprintln!("skipping tcx_attach test on kernel {kernel_version:?}");
return;
}
let _netns = NetNsGuard::new();
// We need a dedicated `Ebpf` instance for each program that we load
// since TCX does not allow the same program ID to be attached multiple
// times to the same interface/direction.
//
// Variables declared within this macro are within a closure scope to avoid
// variable name conflicts.
//
// Yields a tuple of the `Ebpf` which must remain in scope for the duration
// of the test, and the link ID of the attached program.
macro_rules! attach_program_with_link_order_inner {
($program_name:ident, $link_order:expr) => {
let mut ebpf = Ebpf::load(crate::TCX).unwrap();
let $program_name: &mut SchedClassifier =
ebpf.program_mut("tcx_next").unwrap().try_into().unwrap();
$program_name.load().unwrap();
};
}
macro_rules! attach_program_with_link_order {
($program_name:ident, $link_order:expr) => {
attach_program_with_link_order_inner!($program_name, $link_order);
$program_name
.attach_with_options(
"lo",
TcAttachType::Ingress,
TcAttachOptions::TcxOrder($link_order),
)
.unwrap();
};
($program_name:ident, $link_id_name:ident, $link_order:expr) => {
attach_program_with_link_order_inner!($program_name, $link_order);
let $link_id_name = $program_name
.attach_with_options(
"lo",
TcAttachType::Ingress,
TcAttachOptions::TcxOrder($link_order),
)
.unwrap();
};
}
attach_program_with_link_order!(default, LinkOrder::default());
attach_program_with_link_order!(first, LinkOrder::first());
attach_program_with_link_order!(last, last_link_id, LinkOrder::last());
let last_link = last.take_link(last_link_id).unwrap();
attach_program_with_link_order!(before_last, LinkOrder::before_link(&last_link).unwrap());
attach_program_with_link_order!(after_last, LinkOrder::after_link(&last_link).unwrap());
attach_program_with_link_order!(before_default, LinkOrder::before_program(default).unwrap());
attach_program_with_link_order!(after_default, LinkOrder::after_program(default).unwrap());
attach_program_with_link_order!(
before_first,
LinkOrder::before_program_id(unsafe { ProgramId::new(first.info().unwrap().id()) })
);
attach_program_with_link_order!(
after_first,
LinkOrder::after_program_id(unsafe { ProgramId::new(first.info().unwrap().id()) })
);
let expected_order = [
before_first,
first,
after_first,
before_default,
default,
after_default,
before_last,
last,
after_last,
]
.iter()
.map(|program| program.info().unwrap().id())
.collect::<Vec<_>>();
let (revision, got_order) = SchedClassifier::query_tcx("lo", TcAttachType::Ingress).unwrap();
assert_eq!(revision, (expected_order.len() + 1) as u64);
assert_eq!(
got_order.iter().map(|p| p.id()).collect::<Vec<_>>(),
expected_order
);
}

@ -3907,6 +3907,9 @@ pub fn aya::programs::kprobe::KProbeLink::try_from(fd_link: aya::programs::links
impl core::convert::TryFrom<aya::programs::links::FdLink> for aya::programs::perf_event::PerfEventLink
pub type aya::programs::perf_event::PerfEventLink::Error = aya::programs::links::LinkError
pub fn aya::programs::perf_event::PerfEventLink::try_from(fd_link: aya::programs::links::FdLink) -> core::result::Result<Self, Self::Error>
impl core::convert::TryFrom<aya::programs::links::FdLink> for aya::programs::tc::SchedClassifierLink
pub type aya::programs::tc::SchedClassifierLink::Error = aya::programs::links::LinkError
pub fn aya::programs::tc::SchedClassifierLink::try_from(fd_link: aya::programs::links::FdLink) -> core::result::Result<Self, Self::Error>
impl core::convert::TryFrom<aya::programs::links::FdLink> for aya::programs::trace_point::TracePointLink
pub type aya::programs::trace_point::TracePointLink::Error = aya::programs::links::LinkError
pub fn aya::programs::trace_point::TracePointLink::try_from(fd_link: aya::programs::links::FdLink) -> core::result::Result<Self, Self::Error>
@ -3919,6 +3922,9 @@ pub fn aya::programs::xdp::XdpLink::try_from(fd_link: aya::programs::links::FdLi
impl core::convert::TryFrom<aya::programs::perf_event::PerfEventLink> for aya::programs::links::FdLink
pub type aya::programs::links::FdLink::Error = aya::programs::links::LinkError
pub fn aya::programs::links::FdLink::try_from(value: aya::programs::perf_event::PerfEventLink) -> core::result::Result<Self, Self::Error>
impl core::convert::TryFrom<aya::programs::tc::SchedClassifierLink> for aya::programs::links::FdLink
pub type aya::programs::links::FdLink::Error = aya::programs::links::LinkError
pub fn aya::programs::links::FdLink::try_from(value: aya::programs::tc::SchedClassifierLink) -> core::result::Result<Self, Self::Error>
impl core::convert::TryFrom<aya::programs::trace_point::TracePointLink> for aya::programs::links::FdLink
pub type aya::programs::links::FdLink::Error = aya::programs::links::LinkError
pub fn aya::programs::links::FdLink::try_from(value: aya::programs::trace_point::TracePointLink) -> core::result::Result<Self, Self::Error>
@ -3930,6 +3936,9 @@ pub type aya::programs::links::FdLink::Error = aya::programs::links::LinkError
pub fn aya::programs::links::FdLink::try_from(value: aya::programs::xdp::XdpLink) -> core::result::Result<Self, Self::Error>
impl core::fmt::Debug for aya::programs::links::FdLink
pub fn aya::programs::links::FdLink::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl<'a> core::convert::TryFrom<&'a aya::programs::tc::SchedClassifierLink> for &'a aya::programs::links::FdLink
pub type &'a aya::programs::links::FdLink::Error = aya::programs::links::LinkError
pub fn &'a aya::programs::links::FdLink::try_from(value: &'a aya::programs::tc::SchedClassifierLink) -> core::result::Result<Self, Self::Error>
impl core::marker::Freeze for aya::programs::links::FdLink
impl core::marker::Send for aya::programs::links::FdLink
impl core::marker::Sync for aya::programs::links::FdLink
@ -3985,6 +3994,42 @@ impl<T> core::borrow::BorrowMut<T> for aya::programs::links::FdLinkId where T: c
pub fn aya::programs::links::FdLinkId::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::links::FdLinkId
pub fn aya::programs::links::FdLinkId::from(t: T) -> T
pub struct aya::programs::links::LinkOrder
impl aya::programs::links::LinkOrder
pub fn aya::programs::links::LinkOrder::after_link<L: aya::programs::MultiProgLink>(link: &L) -> core::result::Result<Self, aya::programs::links::LinkError>
pub fn aya::programs::links::LinkOrder::after_program<P: aya::programs::MultiProgram>(program: &P) -> core::result::Result<Self, aya::programs::ProgramError>
pub fn aya::programs::links::LinkOrder::after_program_id(id: aya::programs::ProgramId) -> Self
pub fn aya::programs::links::LinkOrder::before_link<L: aya::programs::MultiProgLink>(link: &L) -> core::result::Result<Self, aya::programs::links::LinkError>
pub fn aya::programs::links::LinkOrder::before_program<P: aya::programs::MultiProgram>(program: &P) -> core::result::Result<Self, aya::programs::ProgramError>
pub fn aya::programs::links::LinkOrder::before_program_id(id: aya::programs::ProgramId) -> Self
pub fn aya::programs::links::LinkOrder::first() -> Self
pub fn aya::programs::links::LinkOrder::last() -> Self
impl core::default::Default for aya::programs::links::LinkOrder
pub fn aya::programs::links::LinkOrder::default() -> Self
impl core::fmt::Debug for aya::programs::links::LinkOrder
pub fn aya::programs::links::LinkOrder::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Freeze for aya::programs::links::LinkOrder
impl core::marker::Send for aya::programs::links::LinkOrder
impl core::marker::Sync for aya::programs::links::LinkOrder
impl core::marker::Unpin for aya::programs::links::LinkOrder
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::links::LinkOrder
impl core::panic::unwind_safe::UnwindSafe for aya::programs::links::LinkOrder
impl<T, U> core::convert::Into<U> for aya::programs::links::LinkOrder where U: core::convert::From<T>
pub fn aya::programs::links::LinkOrder::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::links::LinkOrder where U: core::convert::Into<T>
pub type aya::programs::links::LinkOrder::Error = core::convert::Infallible
pub fn aya::programs::links::LinkOrder::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::links::LinkOrder where U: core::convert::TryFrom<T>
pub type aya::programs::links::LinkOrder::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::links::LinkOrder::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> core::any::Any for aya::programs::links::LinkOrder where T: 'static + core::marker::Sized
pub fn aya::programs::links::LinkOrder::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::links::LinkOrder where T: core::marker::Sized
pub fn aya::programs::links::LinkOrder::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::links::LinkOrder where T: core::marker::Sized
pub fn aya::programs::links::LinkOrder::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::links::LinkOrder
pub fn aya::programs::links::LinkOrder::from(t: T) -> T
pub struct aya::programs::links::PinnedLink
impl aya::programs::links::PinnedLink
pub fn aya::programs::links::PinnedLink::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::links::LinkError>
@ -5504,6 +5549,33 @@ pub fn aya::programs::socket_filter::SocketFilterLinkId::borrow_mut(&mut self) -
impl<T> core::convert::From<T> for aya::programs::socket_filter::SocketFilterLinkId
pub fn aya::programs::socket_filter::SocketFilterLinkId::from(t: T) -> T
pub mod aya::programs::tc
pub enum aya::programs::tc::TcAttachOptions
pub aya::programs::tc::TcAttachOptions::Netlink(aya::programs::tc::NlOptions)
pub aya::programs::tc::TcAttachOptions::TcxOrder(aya::programs::links::LinkOrder)
impl core::fmt::Debug for aya::programs::tc::TcAttachOptions
pub fn aya::programs::tc::TcAttachOptions::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Freeze for aya::programs::tc::TcAttachOptions
impl core::marker::Send for aya::programs::tc::TcAttachOptions
impl core::marker::Sync for aya::programs::tc::TcAttachOptions
impl core::marker::Unpin for aya::programs::tc::TcAttachOptions
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcAttachOptions
impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcAttachOptions
impl<T, U> core::convert::Into<U> for aya::programs::tc::TcAttachOptions where U: core::convert::From<T>
pub fn aya::programs::tc::TcAttachOptions::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::tc::TcAttachOptions where U: core::convert::Into<T>
pub type aya::programs::tc::TcAttachOptions::Error = core::convert::Infallible
pub fn aya::programs::tc::TcAttachOptions::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::tc::TcAttachOptions where U: core::convert::TryFrom<T>
pub type aya::programs::tc::TcAttachOptions::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::tc::TcAttachOptions::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> core::any::Any for aya::programs::tc::TcAttachOptions where T: 'static + core::marker::Sized
pub fn aya::programs::tc::TcAttachOptions::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::tc::TcAttachOptions where T: core::marker::Sized
pub fn aya::programs::tc::TcAttachOptions::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::tc::TcAttachOptions where T: core::marker::Sized
pub fn aya::programs::tc::TcAttachOptions::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::tc::TcAttachOptions
pub fn aya::programs::tc::TcAttachOptions::from(t: T) -> T
pub enum aya::programs::tc::TcAttachType
pub aya::programs::tc::TcAttachType::Custom(u32)
pub aya::programs::tc::TcAttachType::Egress
@ -5551,6 +5623,8 @@ impl<T> core::convert::From<T> for aya::programs::tc::TcAttachType
pub fn aya::programs::tc::TcAttachType::from(t: T) -> T
pub enum aya::programs::tc::TcError
pub aya::programs::tc::TcError::AlreadyAttached
pub aya::programs::tc::TcError::InvalidLinkOperation
pub aya::programs::tc::TcError::InvalidTcxAttach(u32)
pub aya::programs::tc::TcError::NetlinkError
pub aya::programs::tc::TcError::NetlinkError::io_error: std::io::error::Error
impl core::convert::From<aya::programs::tc::TcError> for aya::programs::ProgramError
@ -5585,14 +5659,52 @@ impl<T> core::borrow::BorrowMut<T> for aya::programs::tc::TcError where T: core:
pub fn aya::programs::tc::TcError::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::tc::TcError
pub fn aya::programs::tc::TcError::from(t: T) -> T
pub struct aya::programs::tc::NlOptions
pub aya::programs::tc::NlOptions::handle: u32
pub aya::programs::tc::NlOptions::priority: u16
impl core::cmp::Eq for aya::programs::tc::NlOptions
impl core::cmp::PartialEq for aya::programs::tc::NlOptions
pub fn aya::programs::tc::NlOptions::eq(&self, other: &aya::programs::tc::NlOptions) -> bool
impl core::default::Default for aya::programs::tc::NlOptions
pub fn aya::programs::tc::NlOptions::default() -> aya::programs::tc::NlOptions
impl core::fmt::Debug for aya::programs::tc::NlOptions
pub fn aya::programs::tc::NlOptions::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::hash::Hash for aya::programs::tc::NlOptions
pub fn aya::programs::tc::NlOptions::hash<__H: core::hash::Hasher>(&self, state: &mut __H)
impl core::marker::StructuralPartialEq for aya::programs::tc::NlOptions
impl core::marker::Freeze for aya::programs::tc::NlOptions
impl core::marker::Send for aya::programs::tc::NlOptions
impl core::marker::Sync for aya::programs::tc::NlOptions
impl core::marker::Unpin for aya::programs::tc::NlOptions
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::NlOptions
impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::NlOptions
impl<Q, K> equivalent::Equivalent<K> for aya::programs::tc::NlOptions where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
pub fn aya::programs::tc::NlOptions::equivalent(&self, key: &K) -> bool
impl<T, U> core::convert::Into<U> for aya::programs::tc::NlOptions where U: core::convert::From<T>
pub fn aya::programs::tc::NlOptions::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::tc::NlOptions where U: core::convert::Into<T>
pub type aya::programs::tc::NlOptions::Error = core::convert::Infallible
pub fn aya::programs::tc::NlOptions::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::tc::NlOptions where U: core::convert::TryFrom<T>
pub type aya::programs::tc::NlOptions::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::tc::NlOptions::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> core::any::Any for aya::programs::tc::NlOptions where T: 'static + core::marker::Sized
pub fn aya::programs::tc::NlOptions::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::tc::NlOptions where T: core::marker::Sized
pub fn aya::programs::tc::NlOptions::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::tc::NlOptions where T: core::marker::Sized
pub fn aya::programs::tc::NlOptions::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::tc::NlOptions
pub fn aya::programs::tc::NlOptions::from(t: T) -> T
pub struct aya::programs::tc::SchedClassifier
impl aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::attach(&mut self, interface: &str, attach_type: aya::programs::tc::TcAttachType) -> core::result::Result<aya::programs::tc::SchedClassifierLinkId, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::attach_to_link(&mut self, link: aya::programs::tc::SchedClassifierLink) -> core::result::Result<aya::programs::tc::SchedClassifierLinkId, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::attach_with_options(&mut self, interface: &str, attach_type: aya::programs::tc::TcAttachType, options: aya::programs::tc::TcOptions) -> core::result::Result<aya::programs::tc::SchedClassifierLinkId, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::attach_with_options(&mut self, interface: &str, attach_type: aya::programs::tc::TcAttachType, options: aya::programs::tc::TcAttachOptions) -> core::result::Result<aya::programs::tc::SchedClassifierLinkId, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::detach(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result<(), aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::query_tcx(interface: &str, attach_type: aya::programs::tc::TcAttachType) -> core::result::Result<(u64, alloc::vec::Vec<aya::programs::ProgramInfo>), aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result<aya::programs::tc::SchedClassifierLink, aya::programs::ProgramError>
impl aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
@ -5603,6 +5715,8 @@ pub fn aya::programs::tc::SchedClassifier::pin<P: core::convert::AsRef<std::path
pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error>
impl aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
impl aya::programs::MultiProgram for aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<std::os::fd::owned::BorrowedFd<'_>, aya::programs::ProgramError>
impl core::fmt::Debug for aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::ops::drop::Drop for aya::programs::tc::SchedClassifier
@ -5637,18 +5751,29 @@ impl<T> core::convert::From<T> for aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::from(t: T) -> T
pub struct aya::programs::tc::SchedClassifierLink(_)
impl aya::programs::tc::SchedClassifierLink
pub fn aya::programs::tc::SchedClassifierLink::attach_type(&self) -> aya::programs::tc::TcAttachType
pub fn aya::programs::tc::SchedClassifierLink::attach_type(&self) -> core::result::Result<aya::programs::tc::TcAttachType, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifierLink::attached(if_name: &str, attach_type: aya::programs::tc::TcAttachType, priority: u16, handle: u32) -> core::result::Result<Self, std::io::error::Error>
pub fn aya::programs::tc::SchedClassifierLink::handle(&self) -> u32
pub fn aya::programs::tc::SchedClassifierLink::priority(&self) -> u16
pub fn aya::programs::tc::SchedClassifierLink::handle(&self) -> core::result::Result<u32, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifierLink::priority(&self) -> core::result::Result<u16, aya::programs::ProgramError>
impl aya::programs::MultiProgLink for aya::programs::tc::SchedClassifierLink
pub fn aya::programs::tc::SchedClassifierLink::fd(&self) -> core::result::Result<std::os::fd::owned::BorrowedFd<'_>, aya::programs::links::LinkError>
impl aya::programs::links::Link for aya::programs::tc::SchedClassifierLink
pub type aya::programs::tc::SchedClassifierLink::Id = aya::programs::tc::SchedClassifierLinkId
pub fn aya::programs::tc::SchedClassifierLink::detach(self) -> core::result::Result<(), aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifierLink::id(&self) -> Self::Id
impl core::convert::TryFrom<aya::programs::links::FdLink> for aya::programs::tc::SchedClassifierLink
pub type aya::programs::tc::SchedClassifierLink::Error = aya::programs::links::LinkError
pub fn aya::programs::tc::SchedClassifierLink::try_from(fd_link: aya::programs::links::FdLink) -> core::result::Result<Self, Self::Error>
impl core::convert::TryFrom<aya::programs::tc::SchedClassifierLink> for aya::programs::links::FdLink
pub type aya::programs::links::FdLink::Error = aya::programs::links::LinkError
pub fn aya::programs::links::FdLink::try_from(value: aya::programs::tc::SchedClassifierLink) -> core::result::Result<Self, Self::Error>
impl core::fmt::Debug for aya::programs::tc::SchedClassifierLink
pub fn aya::programs::tc::SchedClassifierLink::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::ops::drop::Drop for aya::programs::tc::SchedClassifierLink
pub fn aya::programs::tc::SchedClassifierLink::drop(&mut self)
impl<'a> core::convert::TryFrom<&'a aya::programs::tc::SchedClassifierLink> for &'a aya::programs::links::FdLink
pub type &'a aya::programs::links::FdLink::Error = aya::programs::links::LinkError
pub fn &'a aya::programs::links::FdLink::try_from(value: &'a aya::programs::tc::SchedClassifierLink) -> core::result::Result<Self, Self::Error>
impl core::marker::Freeze for aya::programs::tc::SchedClassifierLink
impl core::marker::Send for aya::programs::tc::SchedClassifierLink
impl core::marker::Sync for aya::programs::tc::SchedClassifierLink
@ -5704,33 +5829,6 @@ impl<T> core::borrow::BorrowMut<T> for aya::programs::tc::SchedClassifierLinkId
pub fn aya::programs::tc::SchedClassifierLinkId::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::tc::SchedClassifierLinkId
pub fn aya::programs::tc::SchedClassifierLinkId::from(t: T) -> T
pub struct aya::programs::tc::TcOptions
pub aya::programs::tc::TcOptions::handle: u32
pub aya::programs::tc::TcOptions::priority: u16
impl core::default::Default for aya::programs::tc::TcOptions
pub fn aya::programs::tc::TcOptions::default() -> aya::programs::tc::TcOptions
impl core::marker::Freeze for aya::programs::tc::TcOptions
impl core::marker::Send for aya::programs::tc::TcOptions
impl core::marker::Sync for aya::programs::tc::TcOptions
impl core::marker::Unpin for aya::programs::tc::TcOptions
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcOptions
impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcOptions
impl<T, U> core::convert::Into<U> for aya::programs::tc::TcOptions where U: core::convert::From<T>
pub fn aya::programs::tc::TcOptions::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::tc::TcOptions where U: core::convert::Into<T>
pub type aya::programs::tc::TcOptions::Error = core::convert::Infallible
pub fn aya::programs::tc::TcOptions::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::tc::TcOptions where U: core::convert::TryFrom<T>
pub type aya::programs::tc::TcOptions::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::tc::TcOptions::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> core::any::Any for aya::programs::tc::TcOptions where T: 'static + core::marker::Sized
pub fn aya::programs::tc::TcOptions::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::tc::TcOptions where T: core::marker::Sized
pub fn aya::programs::tc::TcOptions::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::tc::TcOptions where T: core::marker::Sized
pub fn aya::programs::tc::TcOptions::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::tc::TcOptions
pub fn aya::programs::tc::TcOptions::from(t: T) -> T
pub fn aya::programs::tc::qdisc_add_clsact(if_name: &str) -> core::result::Result<(), std::io::error::Error>
pub fn aya::programs::tc::qdisc_detach_program(if_name: &str, attach_type: aya::programs::tc::TcAttachType, name: &str) -> core::result::Result<(), std::io::error::Error>
pub mod aya::programs::tp_btf
@ -7208,6 +7306,8 @@ impl<T> core::convert::From<T> for aya::programs::tc::TcAttachType
pub fn aya::programs::tc::TcAttachType::from(t: T) -> T
pub enum aya::programs::TcError
pub aya::programs::TcError::AlreadyAttached
pub aya::programs::TcError::InvalidLinkOperation
pub aya::programs::TcError::InvalidTcxAttach(u32)
pub aya::programs::TcError::NetlinkError
pub aya::programs::TcError::NetlinkError::io_error: std::io::error::Error
impl core::convert::From<aya::programs::tc::TcError> for aya::programs::ProgramError
@ -7894,6 +7994,42 @@ impl<T> core::borrow::BorrowMut<T> for aya::programs::kprobe::KProbe where T: co
pub fn aya::programs::kprobe::KProbe::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::kprobe::KProbe
pub fn aya::programs::kprobe::KProbe::from(t: T) -> T
pub struct aya::programs::LinkOrder
impl aya::programs::links::LinkOrder
pub fn aya::programs::links::LinkOrder::after_link<L: aya::programs::MultiProgLink>(link: &L) -> core::result::Result<Self, aya::programs::links::LinkError>
pub fn aya::programs::links::LinkOrder::after_program<P: aya::programs::MultiProgram>(program: &P) -> core::result::Result<Self, aya::programs::ProgramError>
pub fn aya::programs::links::LinkOrder::after_program_id(id: aya::programs::ProgramId) -> Self
pub fn aya::programs::links::LinkOrder::before_link<L: aya::programs::MultiProgLink>(link: &L) -> core::result::Result<Self, aya::programs::links::LinkError>
pub fn aya::programs::links::LinkOrder::before_program<P: aya::programs::MultiProgram>(program: &P) -> core::result::Result<Self, aya::programs::ProgramError>
pub fn aya::programs::links::LinkOrder::before_program_id(id: aya::programs::ProgramId) -> Self
pub fn aya::programs::links::LinkOrder::first() -> Self
pub fn aya::programs::links::LinkOrder::last() -> Self
impl core::default::Default for aya::programs::links::LinkOrder
pub fn aya::programs::links::LinkOrder::default() -> Self
impl core::fmt::Debug for aya::programs::links::LinkOrder
pub fn aya::programs::links::LinkOrder::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Freeze for aya::programs::links::LinkOrder
impl core::marker::Send for aya::programs::links::LinkOrder
impl core::marker::Sync for aya::programs::links::LinkOrder
impl core::marker::Unpin for aya::programs::links::LinkOrder
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::links::LinkOrder
impl core::panic::unwind_safe::UnwindSafe for aya::programs::links::LinkOrder
impl<T, U> core::convert::Into<U> for aya::programs::links::LinkOrder where U: core::convert::From<T>
pub fn aya::programs::links::LinkOrder::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::links::LinkOrder where U: core::convert::Into<T>
pub type aya::programs::links::LinkOrder::Error = core::convert::Infallible
pub fn aya::programs::links::LinkOrder::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::links::LinkOrder where U: core::convert::TryFrom<T>
pub type aya::programs::links::LinkOrder::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::links::LinkOrder::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> core::any::Any for aya::programs::links::LinkOrder where T: 'static + core::marker::Sized
pub fn aya::programs::links::LinkOrder::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::links::LinkOrder where T: core::marker::Sized
pub fn aya::programs::links::LinkOrder::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::links::LinkOrder where T: core::marker::Sized
pub fn aya::programs::links::LinkOrder::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::links::LinkOrder
pub fn aya::programs::links::LinkOrder::from(t: T) -> T
pub struct aya::programs::LircMode2
impl aya::programs::lirc_mode2::LircMode2
pub fn aya::programs::lirc_mode2::LircMode2::attach<T: std::os::fd::owned::AsFd>(&mut self, lircdev: T) -> core::result::Result<aya::programs::lirc_mode2::LircLinkId, aya::programs::ProgramError>
@ -8071,6 +8207,31 @@ impl<T> core::borrow::BorrowMut<T> for aya::programs::ProgramFd where T: core::m
pub fn aya::programs::ProgramFd::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::ProgramFd
pub fn aya::programs::ProgramFd::from(t: T) -> T
pub struct aya::programs::ProgramId(_)
impl aya::programs::ProgramId
pub unsafe fn aya::programs::ProgramId::new(id: u32) -> Self
impl core::marker::Freeze for aya::programs::ProgramId
impl core::marker::Send for aya::programs::ProgramId
impl core::marker::Sync for aya::programs::ProgramId
impl core::marker::Unpin for aya::programs::ProgramId
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::ProgramId
impl core::panic::unwind_safe::UnwindSafe for aya::programs::ProgramId
impl<T, U> core::convert::Into<U> for aya::programs::ProgramId where U: core::convert::From<T>
pub fn aya::programs::ProgramId::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::ProgramId where U: core::convert::Into<T>
pub type aya::programs::ProgramId::Error = core::convert::Infallible
pub fn aya::programs::ProgramId::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::ProgramId where U: core::convert::TryFrom<T>
pub type aya::programs::ProgramId::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::ProgramId::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> core::any::Any for aya::programs::ProgramId where T: 'static + core::marker::Sized
pub fn aya::programs::ProgramId::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::ProgramId where T: core::marker::Sized
pub fn aya::programs::ProgramId::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::ProgramId where T: core::marker::Sized
pub fn aya::programs::ProgramId::borrow_mut(&mut self) -> &mut T
impl<T> core::convert::From<T> for aya::programs::ProgramId
pub fn aya::programs::ProgramId::from(t: T) -> T
pub struct aya::programs::ProgramInfo(_)
impl aya::programs::ProgramInfo
pub fn aya::programs::ProgramInfo::btf_id(&self) -> core::option::Option<u32>
@ -8168,10 +8329,11 @@ pub struct aya::programs::SchedClassifier
impl aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::attach(&mut self, interface: &str, attach_type: aya::programs::tc::TcAttachType) -> core::result::Result<aya::programs::tc::SchedClassifierLinkId, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::attach_to_link(&mut self, link: aya::programs::tc::SchedClassifierLink) -> core::result::Result<aya::programs::tc::SchedClassifierLinkId, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::attach_with_options(&mut self, interface: &str, attach_type: aya::programs::tc::TcAttachType, options: aya::programs::tc::TcOptions) -> core::result::Result<aya::programs::tc::SchedClassifierLinkId, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::attach_with_options(&mut self, interface: &str, attach_type: aya::programs::tc::TcAttachType, options: aya::programs::tc::TcAttachOptions) -> core::result::Result<aya::programs::tc::SchedClassifierLinkId, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::detach(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result<(), aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::query_tcx(interface: &str, attach_type: aya::programs::tc::TcAttachType) -> core::result::Result<(u64, alloc::vec::Vec<aya::programs::ProgramInfo>), aya::programs::ProgramError>
pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result<aya::programs::tc::SchedClassifierLink, aya::programs::ProgramError>
impl aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
@ -8182,6 +8344,8 @@ pub fn aya::programs::tc::SchedClassifier::pin<P: core::convert::AsRef<std::path
pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error>
impl aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
impl aya::programs::MultiProgram for aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<std::os::fd::owned::BorrowedFd<'_>, aya::programs::ProgramError>
impl core::fmt::Debug for aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::ops::drop::Drop for aya::programs::tc::SchedClassifier
@ -8831,6 +8995,14 @@ impl aya::programs::links::Link for aya::programs::xdp::XdpLink
pub type aya::programs::xdp::XdpLink::Id = aya::programs::xdp::XdpLinkId
pub fn aya::programs::xdp::XdpLink::detach(self) -> core::result::Result<(), aya::programs::ProgramError>
pub fn aya::programs::xdp::XdpLink::id(&self) -> Self::Id
pub trait aya::programs::MultiProgLink
pub fn aya::programs::MultiProgLink::fd(&self) -> core::result::Result<std::os::fd::owned::BorrowedFd<'_>, aya::programs::links::LinkError>
impl aya::programs::MultiProgLink for aya::programs::tc::SchedClassifierLink
pub fn aya::programs::tc::SchedClassifierLink::fd(&self) -> core::result::Result<std::os::fd::owned::BorrowedFd<'_>, aya::programs::links::LinkError>
pub trait aya::programs::MultiProgram
pub fn aya::programs::MultiProgram::fd(&self) -> core::result::Result<std::os::fd::owned::BorrowedFd<'_>, aya::programs::ProgramError>
impl aya::programs::MultiProgram for aya::programs::tc::SchedClassifier
pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<std::os::fd::owned::BorrowedFd<'_>, aya::programs::ProgramError>
pub fn aya::programs::loaded_programs() -> impl core::iter::traits::iterator::Iterator<Item = core::result::Result<aya::programs::ProgramInfo, aya::programs::ProgramError>>
pub mod aya::sys
#[non_exhaustive] pub enum aya::sys::Stats

Loading…
Cancel
Save