diff --git a/aya/src/programs/cgroup_device.rs b/aya/src/programs/cgroup_device.rs index 78b01d05..8f6705a5 100644 --- a/aya/src/programs/cgroup_device.rs +++ b/aya/src/programs/cgroup_device.rs @@ -77,6 +77,9 @@ impl CgroupDevice { BPF_CGROUP_DEVICE, None, mode.into(), + Some(0), + None, + None, ) .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", diff --git a/aya/src/programs/cgroup_skb.rs b/aya/src/programs/cgroup_skb.rs index 5054a259..af5b56e7 100644 --- a/aya/src/programs/cgroup_skb.rs +++ b/aya/src/programs/cgroup_skb.rs @@ -105,6 +105,9 @@ impl CgroupSkb { attach_type, None, mode.into(), + Some(0), + None, + None, ) .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", diff --git a/aya/src/programs/cgroup_sock.rs b/aya/src/programs/cgroup_sock.rs index 878c617f..bf66d5f8 100644 --- a/aya/src/programs/cgroup_sock.rs +++ b/aya/src/programs/cgroup_sock.rs @@ -83,6 +83,9 @@ impl CgroupSock { attach_type, None, mode.into(), + Some(0), + None, + None, ) .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", diff --git a/aya/src/programs/cgroup_sock_addr.rs b/aya/src/programs/cgroup_sock_addr.rs index 876037b3..bbca3fa8 100644 --- a/aya/src/programs/cgroup_sock_addr.rs +++ b/aya/src/programs/cgroup_sock_addr.rs @@ -84,6 +84,9 @@ impl CgroupSockAddr { attach_type, None, mode.into(), + Some(0), + None, + None, ) .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", diff --git a/aya/src/programs/cgroup_sockopt.rs b/aya/src/programs/cgroup_sockopt.rs index c67dcc5b..0170b72b 100644 --- a/aya/src/programs/cgroup_sockopt.rs +++ b/aya/src/programs/cgroup_sockopt.rs @@ -81,6 +81,9 @@ impl CgroupSockopt { attach_type, None, mode.into(), + Some(0), + None, + None, ) .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", diff --git a/aya/src/programs/cgroup_sysctl.rs b/aya/src/programs/cgroup_sysctl.rs index 94ccd47f..baa69f6e 100644 --- a/aya/src/programs/cgroup_sysctl.rs +++ b/aya/src/programs/cgroup_sysctl.rs @@ -76,6 +76,9 @@ impl CgroupSysctl { BPF_CGROUP_SYSCTL, None, mode.into(), + Some(0), + None, + None, ) .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index 558bef05..5587d248 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -103,6 +103,9 @@ impl Extension { BPF_CGROUP_INET_INGRESS, Some(btf_id), 0, + None, + None, + None, ) .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", @@ -140,6 +143,9 @@ impl Extension { BPF_CGROUP_INET_INGRESS, Some(btf_id), 0, + None, + None, + None, ) .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", diff --git a/aya/src/programs/links.rs b/aya/src/programs/links.rs index e9afaa87..b855bafb 100644 --- a/aya/src/programs/links.rs +++ b/aya/src/programs/links.rs @@ -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::{MprogLink, MprogProgram, 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,180 @@ pub enum LinkError { SyscallError(#[from] SyscallError), } +/// A [`Link`] identifier, which may or may not be owned by aya. +pub struct LinkId(u32); + +impl LinkId { + /// A wrapper for an arbitrary loaded link specified by its kernel id, + /// unsafe because there is no guarantee provided by aya that the link is + /// still loaded or even exists. + pub unsafe fn new(id: u32) -> Self { + Self(id) + } +} + +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; + } +} + +/// Struct defining the 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. +/// +/// # 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::tcxoptions(LinkOrder::first()); +/// prog.attach_with_options("eth0", TcAttachType::Ingress, options)?; +/// +/// # Ok::<(), aya::EbpfError>(()) +/// ``` +#[derive(Debug)] +pub struct LinkOrder { + pub(crate) id: Option, + pub(crate) fd: Option, + pub(crate) expected_revision: Option, + pub(crate) flags: MprogFlags, +} + +/// Ensure that default link ordering is to be attached last. +impl Default for LinkOrder { + fn default() -> Self { + Self { + id: Some(0), + fd: None, + flags: MprogFlags::AFTER, + expected_revision: None, + } + } +} + +impl LinkOrder { + /// Ensure the link is created before all other links at a given attachment point. + pub fn first() -> Self { + Self { + id: Some(0), + fd: None, + flags: MprogFlags::BEFORE, + expected_revision: None, + } + } + + /// Ensure the link is created after all other links for a given attachment point. + pub fn last() -> Self { + Self { + id: Some(0), + fd: None, + flags: MprogFlags::AFTER, + expected_revision: None, + } + } + + /// Ensure the link is created before the specified aya-owned link for a given attachment point. + pub fn before_link(link: &L) -> Result { + Ok(Self { + id: None, + fd: Some(link.fd()?.as_raw_fd()), + flags: MprogFlags::BEFORE | MprogFlags::LINK, + expected_revision: None, + }) + } + + /// Ensure the link is created after the specified aya-owned link for a given attachment point. + pub fn after_link(link: &L) -> Result { + Ok(Self { + id: None, + fd: Some(link.fd()?.as_raw_fd()), + flags: MprogFlags::AFTER | MprogFlags::LINK, + expected_revision: None, + }) + } + + /// Ensure the link is created before a link specified by its kernel id for a given attachment point. + pub fn before_link_id(id: LinkId) -> Result { + Ok(Self { + id: Some(id.0), + fd: None, + flags: MprogFlags::BEFORE | MprogFlags::LINK | MprogFlags::ID, + expected_revision: None, + }) + } + + /// Ensure the link is created after a link specified by its kernel id for a given attachment point. + pub fn after_link_id(id: LinkId) -> Result { + Ok(Self { + id: Some(id.0), + fd: None, + flags: MprogFlags::AFTER | MprogFlags::LINK | MprogFlags::ID, + expected_revision: None, + }) + } + + /// Ensure the link is created before the specified aya-owned program for a given attachment point. + pub fn before_program(program: &P) -> Result { + Ok(Self { + id: None, + fd: Some(program.fd()?.as_raw_fd()), + flags: MprogFlags::BEFORE, + expected_revision: None, + }) + } + + /// Ensure the link is created after the specified aya-owned program for a given attachment point. + pub fn after_program(program: &P) -> Result { + Ok(Self { + id: None, + fd: Some(program.fd()?.as_raw_fd()), + flags: MprogFlags::AFTER, + expected_revision: None, + }) + } + + /// Ensure the link is created before a program specified by its kernel id for a given attachment point. + pub fn before_program_id(id: ProgramId) -> Self { + Self { + id: Some(id.0), + fd: None, + flags: MprogFlags::BEFORE | MprogFlags::ID, + expected_revision: None, + } + } + + /// Ensure the link is created after a program specified by its kernel id for a given attachment point. + pub fn after_program_id(id: ProgramId) -> Self { + Self { + id: Some(id.0), + fd: None, + flags: MprogFlags::AFTER | MprogFlags::ID, + expected_revision: None, + } + } + + /// set the expected revision for the link, the revision changes + /// with each modification of the list of attached programs. User space + /// can pass an expected revision when creating a new link. The kernel + /// then rejects the update if the revision has changed. + pub fn set_expected_revision(&mut self, revision: u64) { + self.expected_revision = Some(revision); + } +} + #[cfg(test)] mod tests { use std::{cell::RefCell, fs::File, rc::Rc}; diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index fcca69fa..4d29fdf5 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -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}, @@ -239,6 +240,19 @@ impl AsFd for ProgramFd { } /// The various eBPF programs. +/// A [`Program`] identifier, which may or may not be owned by aya. +pub struct ProgramId(u32); + +impl ProgramId { + /// A wrapper for an arbitrary loaded program specified by its kernel id, + /// unsafe because there is no guarantee provided by aya that the program is + /// still loaded or even exists. + pub unsafe fn new(id: u32) -> Self { + Self(id) + } +} + +/// eBPF program type. #[derive(Debug)] pub enum Program { /// A [`KProbe`] program @@ -797,6 +811,61 @@ impl_fd!( CgroupDevice, ); +/// Defines which [`Program`]s support the kernel's +/// generic multi-prog API. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 6.6. +pub trait MprogProgram { + /// Returns a borrowed reference to the file descriptor of a given + /// [`Program`] which has support for the kernel's generic multi-prog API. + fn fd(&self) -> Result, ProgramError>; +} + +macro_rules! impl_mprog_fd { + ($($struct_name:ident),+ $(,)?) => { + $( + impl MprogProgram for $struct_name { + /// Returns the a borrowed reference file descriptor of this Program. + fn fd(&self) -> Result, ProgramError> { + Ok(self.fd()?.as_fd()) + } + } + )+ + } +} + +impl_mprog_fd!(SchedClassifier,); + +/// Defines which [`Link`]s support the kernel's +/// generic multi-prog API. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 6.6. +pub trait MprogLink { + /// Returns a borrowed reference to the file descriptor of a given + /// [`Link`] which has support for the kernel's generic multi-prog API. + fn fd(&self) -> Result, LinkError>; +} + +macro_rules! impl_mproglink_fd { + ($($struct_name:ident),+ $(,)?) => { + $( + impl MprogLink for $struct_name { + /// Returns the a borrowed reference file descriptor of this Program. + fn fd(&self) -> Result, LinkError> { + let link: &FdLink = self.try_into()?; + Ok(link.fd.as_fd()) + } + } + )+ + } +} + +impl_mproglink_fd!(SchedClassifierLink); + macro_rules! impl_program_pin{ ($($struct_name:ident),+ $(,)?) => { $( diff --git a/aya/src/programs/perf_attach.rs b/aya/src/programs/perf_attach.rs index f5818944..2f62a278 100644 --- a/aya/src/programs/perf_attach.rs +++ b/aya/src/programs/perf_attach.rs @@ -75,11 +75,20 @@ pub(crate) fn perf_attach( fd: crate::MockableFd, ) -> Result { if FEATURES.bpf_perf_link() { - let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(fd.as_fd()), BPF_PERF_EVENT, None, 0) - .map_err(|(_, io_error)| SyscallError { - call: "bpf_link_create", - io_error, - })?; + let link_fd = bpf_link_create( + prog_fd, + LinkTarget::Fd(fd.as_fd()), + BPF_PERF_EVENT, + None, + 0, + None, + None, + None, + ) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_link_create", + io_error, + })?; Ok(PerfLinkInner::FdLink(FdLink::new(link_fd))) } else { perf_attach_either(prog_fd, fd, None) diff --git a/aya/src/programs/sk_lookup.rs b/aya/src/programs/sk_lookup.rs index dab0ebc7..8fa516a2 100644 --- a/aya/src/programs/sk_lookup.rs +++ b/aya/src/programs/sk_lookup.rs @@ -65,11 +65,20 @@ 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) - .map_err(|(_, io_error)| SyscallError { - call: "bpf_link_create", - io_error, - })?; + let link_fd = bpf_link_create( + prog_fd, + LinkTarget::Fd(netns_fd), + BPF_SK_LOOKUP, + None, + 0, + None, + None, + None, + ) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_link_create", + io_error, + })?; self.data .links .insert(SkLookupLink::new(FdLink::new(link_fd))) diff --git a/aya/src/programs/tc.rs b/aya/src/programs/tc.rs index c2dd5a13..f9f30187 100644 --- a/aya/src/programs/tc.rs +++ b/aya/src/programs/tc.rs @@ -6,18 +6,26 @@ use std::{ path::Path, }; +use log::debug; use thiserror::Error; +use super::FdLink; 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, Link, LinkError, LinkOrder, ProgramData, ProgramError, }, - programs::{define_link_wrapper, load_program, Link, ProgramData, ProgramError}, sys::{ - netlink_find_filter_with_name, netlink_qdisc_add_clsact, netlink_qdisc_attach, - netlink_qdisc_detach, + bpf_link_create, bpf_link_get_info_by_fd, bpf_link_update, netlink_find_filter_with_name, + netlink_qdisc_add_clsact, netlink_qdisc_attach, netlink_qdisc_detach, LinkTarget, + SyscallError, }, - util::{ifindex_from_ifname, tc_handler_make}, + util::{ifindex_from_ifname, tc_handler_make, KernelVersion}, VerifierLogLevel, }; @@ -89,6 +97,12 @@ 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 + #[error("tcx links can only be attached to ingress or egress")] + InvalidTcxAttach, + /// program was loaded via tcx not netlink + #[error("program was loaded via tcx not netlink")] + InvalidTcLink, } impl TcAttachType { @@ -99,11 +113,43 @@ impl TcAttachType { Self::Egress => tc_handler_make(TC_H_CLSACT, TC_H_MIN_EGRESS), } } + + pub(crate) fn tcx_attach(&self) -> Result { + match self { + Self::Ingress => Ok(BPF_TCX_INGRESS), + Self::Egress => Ok(BPF_TCX_EGRESS), + Self::Custom(_) => Err(TcError::InvalidTcxAttach), + } + } } -/// Options for SchedClassifier attach -#[derive(Default)] -pub struct TcOptions { +/// Options for a SchedClassifier attach operation. The options vary based on +/// what is supported by the current kernel. Kernels older than 6.6 must utilize +/// netlink for attachements, while newer kernels can utilize the modern TCX eBPF +/// link type which support's the kernel's mprog ordering api. +pub enum TcAttachOptions { + /// Netlink attach options. + NlOptions(NlOptions), + /// Tcx attach options. + TCXOptions(LinkOrder), +} + +impl TcAttachOptions { + /// Create a new set of tcx attach options with a specified link ordering + pub fn tcxoptions(order: LinkOrder) -> Self { + Self::TCXOptions(order) + } + + /// Create a new set of netlink attach options with a specified priority and + /// handle. + pub fn nloptions(nl: NlOptions) -> Self { + Self::NlOptions(nl) + } +} + +/// 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,14 +164,16 @@ 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` using the TCX link + /// API in the first position by default, revert to the legacy netlink API otherwise. + /// For fine-grain 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 + /// [`TcError::NetlinkError`] is returned if attaching via netlink fails. A + /// common cause of failure is not having added the `clsact` qdisc to the given /// interface, seeĀ [`qdisc_add_clsact`] /// pub fn attach( @@ -133,10 +181,24 @@ impl SchedClassifier { interface: &str, attach_type: TcAttachType, ) -> Result { - self.attach_with_options(interface, attach_type, TcOptions::default()) + if KernelVersion::current().unwrap() >= KernelVersion::new(6, 6, 0) { + debug!("attaching schedClassifier program via txc link API"); + self.attach_with_options( + interface, + attach_type, + TcAttachOptions::TCXOptions(LinkOrder::default()), + ) + } else { + debug!("attaching SchedClassifier program via netlink API"); + self.attach_with_options( + interface, + attach_type, + TcAttachOptions::NlOptions(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 +212,11 @@ impl SchedClassifier { &mut self, interface: &str, attach_type: TcAttachType, - options: TcOptions, + options: TcAttachOptions, ) -> Result { 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,46 +226,100 @@ impl SchedClassifier { &mut self, link: SchedClassifierLink, ) -> Result { - let TcLink { - if_index, - attach_type, - priority, - handle, - } = link.into_inner(); - self.do_attach(if_index, attach_type, TcOptions { priority, handle }, false) + 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, + }) => self.do_attach( + if_index, + attach_type, + TcAttachOptions::NlOptions(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 { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - 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, - &attach_type, - prog_fd, - &name, - options.priority, - options.handle, - create, - ) - } - .map_err(|io_error| TcError::NetlinkError { io_error })?; - self.data.links.insert(SchedClassifierLink::new(TcLink { - if_index, - attach_type, - priority, - handle, - })) + match options { + TcAttachOptions::NlOptions(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 as i32, + &attach_type, + prog_fd, + &name, + options.priority, + options.handle, + create, + ) + } + .map_err(|io_error| TcError::NetlinkError { io_error })?; + + self.data + .links + .insert(SchedClassifierLink::new(TcLinkInner::NlLink(NlLink { + if_index, + attach_type, + priority, + handle, + }))) + } + TcAttachOptions::TCXOptions(options) => { + let link_fd = bpf_link_create( + prog_fd, + LinkTarget::IfIndex(if_index), + attach_type.tcx_attach()?, + None, + options.flags.bits(), + options.id, + options.fd, + None, + ) + .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. @@ -237,39 +353,111 @@ impl SchedClassifier { } #[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(::Id), + NlLinkId(::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 { + if let TcLinkInner::FdLink(fd) = value.inner() { + Ok(fd) + } else { + Err(LinkError::InvalidLink) + } + } +} + +impl TryFrom for FdLink { + type Error = LinkError; + + fn try_from(value: SchedClassifierLink) -> Result { + if let TcLinkInner::FdLink(fd) = value.into_inner() { + Ok(fd) + } else { + Err(LinkError::InvalidLink) + } + } +} + +impl TryFrom for SchedClassifierLink { + type Error = LinkError; + + fn try_from(fd_link: FdLink) -> Result { + // unwrap of fd_link.fd will not panic since it's only None when being dropped. + 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 +499,39 @@ impl SchedClassifierLink { handle: u32, ) -> Result { 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 { + if let TcLinkInner::NlLink(n) = self.inner() { + Ok(n.attach_type) + } else { + Err(TcError::InvalidTcLink.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 { + if let TcLinkInner::NlLink(n) = self.inner() { + Ok(n.priority) + } else { + Err(TcError::InvalidTcLink.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 { + if let TcLinkInner::NlLink(n) = self.inner() { + Ok(n.handle) + } else { + Err(TcError::InvalidTcLink.into()) + } } } diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index 5d49f4f1..223fe539 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -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,9 @@ impl Xdp { attach_type, None, flags.bits(), + None, + None, + None, ) .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 2d305246..d0949fb0 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -379,12 +379,16 @@ pub(crate) enum LinkTarget<'f> { } // since kernel 5.7 +#[allow(clippy::too_many_arguments)] pub(crate) fn bpf_link_create( prog_fd: BorrowedFd<'_>, target: LinkTarget<'_>, attach_type: bpf_attach_type, btf_id: Option, flags: u32, + relative_id: Option, + relative_fd: Option, + expected_revision: Option, ) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; @@ -399,11 +403,36 @@ 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 + if let Some(expected_revision) = expected_revision { + attr.link_create.__bindgen_anon_3.tcx.expected_revision = expected_revision; + } + + match (relative_fd, relative_id) { + (Some(fd), None) => { + attr.link_create + .__bindgen_anon_3 + .tcx + .__bindgen_anon_1 + .relative_fd = fd as u32; + } + (None, Some(id)) => { + attr.link_create + .__bindgen_anon_3 + .tcx + .__bindgen_anon_1 + .relative_id = id; + } + _ => {} + }; + // SAFETY: BPF_LINK_CREATE returns a new file descriptor. unsafe { fd_sys_bpf(bpf_cmd::BPF_LINK_CREATE, &mut attr) } } @@ -826,7 +855,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, None, None), // Returns EINVAL if unsupported. EBADF if supported. Err((_, e)) if e.raw_os_error() == Some(libc::EBADF), ) diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index c9ff22f4..dd7d6756 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -3929,6 +3929,9 @@ pub fn aya::programs::kprobe::KProbeLink::try_from(fd_link: aya::programs::links impl core::convert::TryFrom 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 +impl core::convert::TryFrom 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 impl core::convert::TryFrom 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 @@ -3941,6 +3944,9 @@ pub fn aya::programs::xdp::XdpLink::try_from(fd_link: aya::programs::links::FdLi impl core::convert::TryFrom 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 +impl core::convert::TryFrom 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 impl core::convert::TryFrom 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 @@ -3952,6 +3958,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 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 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 @@ -4009,6 +4018,70 @@ impl core::borrow::BorrowMut for aya::programs::links::FdLinkId where T: c pub fn aya::programs::links::FdLinkId::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::programs::links::FdLinkId pub fn aya::programs::links::FdLinkId::from(t: T) -> T +pub struct aya::programs::links::LinkId(_) +impl aya::programs::links::LinkId +pub unsafe fn aya::programs::links::LinkId::new(id: u32) -> Self +impl core::marker::Freeze for aya::programs::links::LinkId +impl core::marker::Send for aya::programs::links::LinkId +impl core::marker::Sync for aya::programs::links::LinkId +impl core::marker::Unpin for aya::programs::links::LinkId +impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::links::LinkId +impl core::panic::unwind_safe::UnwindSafe for aya::programs::links::LinkId +impl core::convert::Into for aya::programs::links::LinkId where U: core::convert::From +pub fn aya::programs::links::LinkId::into(self) -> U +impl core::convert::TryFrom for aya::programs::links::LinkId where U: core::convert::Into +pub type aya::programs::links::LinkId::Error = core::convert::Infallible +pub fn aya::programs::links::LinkId::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::programs::links::LinkId where U: core::convert::TryFrom +pub type aya::programs::links::LinkId::Error = >::Error +pub fn aya::programs::links::LinkId::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::programs::links::LinkId where T: 'static + core::marker::Sized +pub fn aya::programs::links::LinkId::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::programs::links::LinkId where T: core::marker::Sized +pub fn aya::programs::links::LinkId::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::programs::links::LinkId where T: core::marker::Sized +pub fn aya::programs::links::LinkId::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::programs::links::LinkId +pub fn aya::programs::links::LinkId::from(t: T) -> T +pub struct aya::programs::links::LinkOrder +impl aya::programs::links::LinkOrder +pub fn aya::programs::links::LinkOrder::after_link(link: &L) -> core::result::Result +pub fn aya::programs::links::LinkOrder::after_link_id(id: aya::programs::links::LinkId) -> core::result::Result +pub fn aya::programs::links::LinkOrder::after_program(program: &P) -> core::result::Result +pub fn aya::programs::links::LinkOrder::after_program_id(id: aya::programs::ProgramId) -> Self +pub fn aya::programs::links::LinkOrder::before_link(link: &L) -> core::result::Result +pub fn aya::programs::links::LinkOrder::before_link_id(id: aya::programs::links::LinkId) -> core::result::Result +pub fn aya::programs::links::LinkOrder::before_program(program: &P) -> core::result::Result +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 +pub fn aya::programs::links::LinkOrder::set_expected_revision(&mut self, revision: u64) +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 core::convert::Into for aya::programs::links::LinkOrder where U: core::convert::From +pub fn aya::programs::links::LinkOrder::into(self) -> U +impl core::convert::TryFrom for aya::programs::links::LinkOrder where U: core::convert::Into +pub type aya::programs::links::LinkOrder::Error = core::convert::Infallible +pub fn aya::programs::links::LinkOrder::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::programs::links::LinkOrder where U: core::convert::TryFrom +pub type aya::programs::links::LinkOrder::Error = >::Error +pub fn aya::programs::links::LinkOrder::try_into(self) -> core::result::Result>::Error> +impl 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 core::borrow::Borrow for aya::programs::links::LinkOrder where T: core::marker::Sized +pub fn aya::programs::links::LinkOrder::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::programs::links::LinkOrder where T: core::marker::Sized +pub fn aya::programs::links::LinkOrder::borrow_mut(&mut self) -> &mut T +impl core::convert::From 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>(path: P) -> core::result::Result @@ -5550,6 +5623,34 @@ pub fn aya::programs::socket_filter::SocketFilterLinkId::borrow_mut(&mut self) - impl core::convert::From 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::NlOptions(aya::programs::tc::NlOptions) +pub aya::programs::tc::TcAttachOptions::TCXOptions(aya::programs::links::LinkOrder) +impl aya::programs::tc::TcAttachOptions +pub fn aya::programs::tc::TcAttachOptions::nloptions(nl: aya::programs::tc::NlOptions) -> Self +pub fn aya::programs::tc::TcAttachOptions::tcxoptions(order: aya::programs::links::LinkOrder) -> Self +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 core::convert::Into for aya::programs::tc::TcAttachOptions where U: core::convert::From +pub fn aya::programs::tc::TcAttachOptions::into(self) -> U +impl core::convert::TryFrom for aya::programs::tc::TcAttachOptions where U: core::convert::Into +pub type aya::programs::tc::TcAttachOptions::Error = core::convert::Infallible +pub fn aya::programs::tc::TcAttachOptions::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::programs::tc::TcAttachOptions where U: core::convert::TryFrom +pub type aya::programs::tc::TcAttachOptions::Error = >::Error +pub fn aya::programs::tc::TcAttachOptions::try_into(self) -> core::result::Result>::Error> +impl 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 core::borrow::Borrow for aya::programs::tc::TcAttachOptions where T: core::marker::Sized +pub fn aya::programs::tc::TcAttachOptions::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::programs::tc::TcAttachOptions where T: core::marker::Sized +pub fn aya::programs::tc::TcAttachOptions::borrow_mut(&mut self) -> &mut T +impl core::convert::From 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 @@ -5599,6 +5700,8 @@ impl core::convert::From 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::InvalidTcLink +pub aya::programs::tc::TcError::InvalidTcxAttach pub aya::programs::tc::TcError::NetlinkError pub aya::programs::tc::TcError::NetlinkError::io_error: std::io::error::Error impl core::convert::From for aya::programs::ProgramError @@ -5633,11 +5736,50 @@ impl core::borrow::BorrowMut for aya::programs::tc::TcError where T: core: pub fn aya::programs::tc::TcError::borrow_mut(&mut self) -> &mut T impl core::convert::From 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 equivalent::Equivalent for aya::programs::tc::NlOptions where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow + core::marker::Sized +pub fn aya::programs::tc::NlOptions::equivalent(&self, key: &K) -> bool +impl hashbrown::Equivalent for aya::programs::tc::NlOptions where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow + core::marker::Sized +pub fn aya::programs::tc::NlOptions::equivalent(&self, key: &K) -> bool +impl core::convert::Into for aya::programs::tc::NlOptions where U: core::convert::From +pub fn aya::programs::tc::NlOptions::into(self) -> U +impl core::convert::TryFrom for aya::programs::tc::NlOptions where U: core::convert::Into +pub type aya::programs::tc::NlOptions::Error = core::convert::Infallible +pub fn aya::programs::tc::NlOptions::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::programs::tc::NlOptions where U: core::convert::TryFrom +pub type aya::programs::tc::NlOptions::Error = >::Error +pub fn aya::programs::tc::NlOptions::try_into(self) -> core::result::Result>::Error> +impl 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 core::borrow::Borrow for aya::programs::tc::NlOptions where T: core::marker::Sized +pub fn aya::programs::tc::NlOptions::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::programs::tc::NlOptions where T: core::marker::Sized +pub fn aya::programs::tc::NlOptions::borrow_mut(&mut self) -> &mut T +impl core::convert::From 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 pub fn aya::programs::tc::SchedClassifier::attach_to_link(&mut self, link: aya::programs::tc::SchedClassifierLink) -> core::result::Result -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 +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 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>(path: P) -> core::result::Result pub fn aya::programs::tc::SchedClassifier::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> @@ -5651,6 +5793,8 @@ pub fn aya::programs::tc::SchedClassifier::pin 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::MprogProgram for aya::programs::tc::SchedClassifier +pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result, 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 @@ -5685,18 +5829,29 @@ impl core::convert::From 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 pub fn aya::programs::tc::SchedClassifierLink::attached(if_name: &str, attach_type: aya::programs::tc::TcAttachType, priority: u16, handle: u32) -> core::result::Result -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 +pub fn aya::programs::tc::SchedClassifierLink::priority(&self) -> core::result::Result +impl aya::programs::MprogLink for aya::programs::tc::SchedClassifierLink +pub fn aya::programs::tc::SchedClassifierLink::fd(&self) -> core::result::Result, 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 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 +impl core::convert::TryFrom 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 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 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 @@ -5754,33 +5909,6 @@ impl core::borrow::BorrowMut for aya::programs::tc::SchedClassifierLinkId pub fn aya::programs::tc::SchedClassifierLinkId::borrow_mut(&mut self) -> &mut T impl core::convert::From 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 core::convert::Into for aya::programs::tc::TcOptions where U: core::convert::From -pub fn aya::programs::tc::TcOptions::into(self) -> U -impl core::convert::TryFrom for aya::programs::tc::TcOptions where U: core::convert::Into -pub type aya::programs::tc::TcOptions::Error = core::convert::Infallible -pub fn aya::programs::tc::TcOptions::try_from(value: U) -> core::result::Result>::Error> -impl core::convert::TryInto for aya::programs::tc::TcOptions where U: core::convert::TryFrom -pub type aya::programs::tc::TcOptions::Error = >::Error -pub fn aya::programs::tc::TcOptions::try_into(self) -> core::result::Result>::Error> -impl 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 core::borrow::Borrow for aya::programs::tc::TcOptions where T: core::marker::Sized -pub fn aya::programs::tc::TcOptions::borrow(&self) -> &T -impl core::borrow::BorrowMut for aya::programs::tc::TcOptions where T: core::marker::Sized -pub fn aya::programs::tc::TcOptions::borrow_mut(&mut self) -> &mut T -impl core::convert::From 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 @@ -7268,6 +7396,8 @@ impl core::convert::From 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::InvalidTcLink +pub aya::programs::TcError::InvalidTcxAttach pub aya::programs::TcError::NetlinkError pub aya::programs::TcError::NetlinkError::io_error: std::io::error::Error impl core::convert::From for aya::programs::ProgramError @@ -7954,6 +8084,45 @@ impl core::borrow::BorrowMut for aya::programs::kprobe::KProbe where T: co pub fn aya::programs::kprobe::KProbe::borrow_mut(&mut self) -> &mut T impl core::convert::From 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(link: &L) -> core::result::Result +pub fn aya::programs::links::LinkOrder::after_link_id(id: aya::programs::links::LinkId) -> core::result::Result +pub fn aya::programs::links::LinkOrder::after_program(program: &P) -> core::result::Result +pub fn aya::programs::links::LinkOrder::after_program_id(id: aya::programs::ProgramId) -> Self +pub fn aya::programs::links::LinkOrder::before_link(link: &L) -> core::result::Result +pub fn aya::programs::links::LinkOrder::before_link_id(id: aya::programs::links::LinkId) -> core::result::Result +pub fn aya::programs::links::LinkOrder::before_program(program: &P) -> core::result::Result +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 +pub fn aya::programs::links::LinkOrder::set_expected_revision(&mut self, revision: u64) +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 core::convert::Into for aya::programs::links::LinkOrder where U: core::convert::From +pub fn aya::programs::links::LinkOrder::into(self) -> U +impl core::convert::TryFrom for aya::programs::links::LinkOrder where U: core::convert::Into +pub type aya::programs::links::LinkOrder::Error = core::convert::Infallible +pub fn aya::programs::links::LinkOrder::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::programs::links::LinkOrder where U: core::convert::TryFrom +pub type aya::programs::links::LinkOrder::Error = >::Error +pub fn aya::programs::links::LinkOrder::try_into(self) -> core::result::Result>::Error> +impl 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 core::borrow::Borrow for aya::programs::links::LinkOrder where T: core::marker::Sized +pub fn aya::programs::links::LinkOrder::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::programs::links::LinkOrder where T: core::marker::Sized +pub fn aya::programs::links::LinkOrder::borrow_mut(&mut self) -> &mut T +impl core::convert::From 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(&mut self, lircdev: T) -> core::result::Result @@ -8131,6 +8300,31 @@ impl core::borrow::BorrowMut for aya::programs::ProgramFd where T: core::m pub fn aya::programs::ProgramFd::borrow_mut(&mut self) -> &mut T impl core::convert::From 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 core::convert::Into for aya::programs::ProgramId where U: core::convert::From +pub fn aya::programs::ProgramId::into(self) -> U +impl core::convert::TryFrom for aya::programs::ProgramId where U: core::convert::Into +pub type aya::programs::ProgramId::Error = core::convert::Infallible +pub fn aya::programs::ProgramId::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::programs::ProgramId where U: core::convert::TryFrom +pub type aya::programs::ProgramId::Error = >::Error +pub fn aya::programs::ProgramId::try_into(self) -> core::result::Result>::Error> +impl 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 core::borrow::Borrow for aya::programs::ProgramId where T: core::marker::Sized +pub fn aya::programs::ProgramId::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::programs::ProgramId where T: core::marker::Sized +pub fn aya::programs::ProgramId::borrow_mut(&mut self) -> &mut T +impl core::convert::From 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 @@ -8228,7 +8422,7 @@ 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 pub fn aya::programs::tc::SchedClassifier::attach_to_link(&mut self, link: aya::programs::tc::SchedClassifierLink) -> core::result::Result -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 +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 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>(path: P) -> core::result::Result pub fn aya::programs::tc::SchedClassifier::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> @@ -8242,6 +8436,8 @@ pub fn aya::programs::tc::SchedClassifier::pin 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::MprogProgram for aya::programs::tc::SchedClassifier +pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result, 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 @@ -8891,6 +9087,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::MprogLink +pub fn aya::programs::MprogLink::fd(&self) -> core::result::Result, aya::programs::links::LinkError> +impl aya::programs::MprogLink for aya::programs::tc::SchedClassifierLink +pub fn aya::programs::tc::SchedClassifierLink::fd(&self) -> core::result::Result, aya::programs::links::LinkError> +pub trait aya::programs::MprogProgram +pub fn aya::programs::MprogProgram::fd(&self) -> core::result::Result, aya::programs::ProgramError> +impl aya::programs::MprogProgram for aya::programs::tc::SchedClassifier +pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result, aya::programs::ProgramError> pub fn aya::programs::loaded_programs() -> impl core::iter::traits::iterator::Iterator> pub mod aya::sys #[non_exhaustive] pub enum aya::sys::Stats