diff --git a/aya/src/programs/links.rs b/aya/src/programs/links.rs index 62f40102d..0a8823c8a 100644 --- a/aya/src/programs/links.rs +++ b/aya/src/programs/links.rs @@ -648,12 +648,17 @@ bitflags::bitflags! { /// /// ```no_run /// # let mut bpf = aya::Ebpf::load(&[])?; -/// use aya::programs::{tc, SchedClassifier, TcAttachType, tc::TcAttachOptions, LinkOrder}; +/// use aya::programs::{LinkOrder, SchedClassifier, SchedClassifierAttachment, TcxAttachType}; /// /// 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)?; +/// prog.attach( +/// "eth0", +/// SchedClassifierAttachment::Tcx { +/// attach_type: TcxAttachType::Ingress, +/// link_order: LinkOrder::first(), +/// }, +/// )?; /// /// # Ok::<(), aya::EbpfError>(()) /// ``` diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 14e3d31a7..668cc5551 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -121,7 +121,10 @@ pub use crate::programs::{ sk_skb::{SkSkb, SkSkbKind}, sock_ops::SockOps, socket_filter::{SocketFilter, SocketFilterError}, - tc::{SchedClassifier, TcAttachType, TcError, TcHandle}, + tc::{ + NetkitAttachType, SchedClassifier, SchedClassifierAttachment, TcAttachType, TcError, + TcHandle, TcxAttachType, + }, tp_btf::BtfTracePoint, trace_point::{TracePoint, TracePointError}, uprobe::{UProbe, UProbeError}, diff --git a/aya/src/programs/tc.rs b/aya/src/programs/tc.rs index a6eb16bf8..09bcaae2f 100644 --- a/aya/src/programs/tc.rs +++ b/aya/src/programs/tc.rs @@ -3,7 +3,7 @@ use std::{ffi::CString, io, os::fd::AsFd as _, path::Path}; use aya_obj::generated::{ TC_H_CLSACT, TC_H_MIN_EGRESS, TC_H_MIN_INGRESS, - bpf_attach_type::{self, BPF_TCX_EGRESS, BPF_TCX_INGRESS}, + bpf_attach_type::{self, BPF_NETKIT_PEER, BPF_NETKIT_PRIMARY, BPF_TCX_EGRESS, BPF_TCX_INGRESS}, bpf_link_type, bpf_prog_type::BPF_PROG_TYPE_SCHED_CLS, }; @@ -14,18 +14,42 @@ use crate::{ VerifierLogLevel, programs::{ Link, LinkError, LinkOrder, ProgramData, ProgramError, ProgramType, define_link_wrapper, - id_as_key, impl_try_from_fdlink, impl_try_into_fdlink, load_program_without_attach_type, - query, + id_as_key, impl_try_into_fdlink, load_program_without_attach_type, query, }, sys::{ BpfLinkCreateArgs, LinkTarget, NetlinkError, NetlinkSocket, ProgQueryTarget, SyscallError, bpf_link_create, bpf_link_update, bpf_prog_get_fd_by_id, netlink_find_filter_with_name, netlink_qdisc_add_clsact, netlink_qdisc_attach, netlink_qdisc_detach, }, - util::{KernelVersion, ifindex_from_ifname, tc_handler_make}, + util::{ifindex_from_ifname, tc_handler_make}, }; -/// Traffic control attach type. +/// Attachment configuration for [`SchedClassifier`] programs. +pub enum SchedClassifierAttachment { + /// Attach as a legacy TC filter using netlink. + Tc { + /// The legacy TC hook to attach to. + attach_type: TcAttachType, + /// Netlink attach options. + options: NlOptions, + }, + /// Attach to TCX using the eBPF link interface. + Tcx { + /// The TCX hook to attach to. + attach_type: TcxAttachType, + /// Multi-prog link ordering. + link_order: LinkOrder, + }, + /// Attach to a Netkit device using the eBPF link interface. + Netkit { + /// The Netkit hook to attach to. + attach_type: NetkitAttachType, + /// Multi-prog link ordering. + link_order: LinkOrder, + }, +} + +/// Traffic control attach type using netlink. #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] pub enum TcAttachType { /// Attach to ingress. @@ -36,6 +60,45 @@ pub enum TcAttachType { Custom(u32), } +/// Traffic control attach type using eBPF link interface. +/// Requires kernels >= 6.6.0. +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum TcxAttachType { + /// Attach to ingress. + Ingress, + /// Attach to egress. + Egress, +} + +impl TcxAttachType { + pub(crate) const fn bpf_attach_type(self) -> bpf_attach_type { + match self { + Self::Ingress => BPF_TCX_INGRESS, + Self::Egress => BPF_TCX_EGRESS, + } + } +} + +/// Netkit attach type using eBPF link interface. +/// Requires kernels >= 6.7.0. +/// Can only be attached to netkit devices. +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum NetkitAttachType { + /// Attach to primary. + Primary, + /// Attach to peer. + Peer, +} + +impl NetkitAttachType { + pub(crate) const fn bpf_attach_type(self) -> bpf_attach_type { + match self { + Self::Primary => BPF_NETKIT_PRIMARY, + Self::Peer => BPF_NETKIT_PEER, + } + } +} + /// A network traffic control classifier. /// /// [`SchedClassifier`] programs can be used to inspect, filter or redirect @@ -47,7 +110,13 @@ pub enum TcAttachType { /// /// # Minimum kernel version /// -/// The minimum kernel version required to use this feature is 4.1. +/// Legacy TC attachments require kernel 4.1 or later. TCX attachments require +/// kernel 6.6 or later. Netkit attachments require kernel 6.7 or later and a +/// netkit device. +/// +/// # Legacy TC attachment +/// +/// Legacy TC attachments use netlink and require the `clsact` qdisc. /// /// ```no_run /// # #[derive(Debug, thiserror::Error)] @@ -64,15 +133,100 @@ pub enum TcAttachType { /// # Ebpf(#[from] aya::EbpfError) /// # } /// # let mut bpf = aya::Ebpf::load(&[])?; -/// use aya::programs::{tc, SchedClassifier, TcAttachType}; +/// use aya::programs::{tc::{self, NlOptions}, SchedClassifier, SchedClassifierAttachment, TcAttachType}; /// /// // the clsact qdisc needs to be added before SchedClassifier programs can be -/// // attached +/// // attached with legacy TC /// tc::qdisc_add_clsact("eth0")?; /// /// let prog: &mut SchedClassifier = bpf.program_mut("redirect_ingress").unwrap().try_into()?; /// prog.load()?; -/// prog.attach("eth0", TcAttachType::Ingress)?; +/// prog.attach( +/// "eth0", +/// SchedClassifierAttachment::Tc { +/// attach_type: TcAttachType::Ingress, +/// options: NlOptions::default(), +/// }, +/// )?; +/// +/// # Ok::<(), Error>(()) +/// ``` +/// +/// # TCX attachment +/// +/// TCX attachments use eBPF links and support multi-prog ordering. +/// +/// ```no_run +/// # #[derive(Debug, thiserror::Error)] +/// # enum Error { +/// # #[error(transparent)] +/// # IO(#[from] std::io::Error), +/// # #[error(transparent)] +/// # Map(#[from] aya::maps::MapError), +/// # #[error(transparent)] +/// # Program(#[from] aya::programs::ProgramError), +/// # #[error(transparent)] +/// # Tc(#[from] aya::programs::tc::TcError), +/// # #[error(transparent)] +/// # Ebpf(#[from] aya::EbpfError) +/// # } +/// # let mut bpf = aya::Ebpf::load(&[])?; +/// use aya::programs::{LinkOrder, SchedClassifier, SchedClassifierAttachment, TcxAttachType}; +/// +/// let prog: &mut SchedClassifier = bpf.program_mut("redirect_ingress").unwrap().try_into()?; +/// prog.load()?; +/// prog.attach( +/// "eth0", +/// SchedClassifierAttachment::Tcx { +/// attach_type: TcxAttachType::Ingress, +/// link_order: LinkOrder::default(), +/// }, +/// )?; +/// +/// # Ok::<(), Error>(()) +/// ``` +/// +/// # Netkit attachment +/// +/// Netkit attachments use eBPF links and support multi-prog ordering. The +/// interface must be a netkit device. +/// +/// ```no_run +/// # #[derive(Debug, thiserror::Error)] +/// # enum Error { +/// # #[error(transparent)] +/// # IO(#[from] std::io::Error), +/// # #[error(transparent)] +/// # Map(#[from] aya::maps::MapError), +/// # #[error(transparent)] +/// # Program(#[from] aya::programs::ProgramError), +/// # #[error(transparent)] +/// # Tc(#[from] aya::programs::tc::TcError), +/// # #[error(transparent)] +/// # Ebpf(#[from] aya::EbpfError) +/// # } +/// # let mut bpf = aya::Ebpf::load(&[])?; +/// use aya::programs::{LinkOrder, NetkitAttachType, SchedClassifier, SchedClassifierAttachment}; +/// +/// let primary_prog: &mut SchedClassifier = bpf.program_mut("primary").unwrap().try_into()?; +/// primary_prog.load()?; +/// primary_prog.attach( +/// "nk0", +/// SchedClassifierAttachment::Netkit { +/// attach_type: NetkitAttachType::Primary, +/// link_order: LinkOrder::default(), +/// }, +/// )?; +/// let peer_prog: &mut SchedClassifier = bpf.program_mut("peer").unwrap().try_into()?; +/// peer_prog.load()?; +/// // Peer attachment still occurs on the primary interface +/// peer_prog.attach( +/// "nk0", +/// SchedClassifierAttachment::Netkit { +/// attach_type: NetkitAttachType::Peer, +/// link_order: LinkOrder::default(), +/// }, +/// )?; /// /// # Ok::<(), Error>(()) /// ``` @@ -97,13 +251,8 @@ 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")] + /// operation not supported for programs loaded via tcx or netkit. + #[error("operation not supported for fd-backed TC links")] InvalidLinkOperation, } @@ -115,28 +264,6 @@ impl TcAttachType { Self::Egress => tc_handler_make(TC_H_CLSACT, TC_H_MIN_EGRESS), } } - - pub(crate) const fn tcx_attach_type(self) -> Result { - 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), } /// A TC filter handle in `major:minor` form. @@ -217,11 +344,7 @@ impl SchedClassifier { /// 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`]. + /// TCX requires kernels >= 6.6.0 and netkit requires kernels >= 6.7.0. /// /// The returned value can be used to detach, see [`SchedClassifier::detach`]. /// @@ -235,86 +358,35 @@ impl SchedClassifier { pub fn attach( &mut self, interface: &str, - attach_type: TcAttachType, + attachment: SchedClassifierAttachment, ) -> Result { - if !matches!(attach_type, TcAttachType::Custom(_)) && KernelVersion::at_least(6, 6, 0) { - self.attach_with_options( - interface, + let if_index = ifindex_from_ifname(interface).map_err(TcError::IoError)?; + match attachment { + SchedClassifierAttachment::Tc { attach_type, - TcAttachOptions::TcxOrder(LinkOrder::default()), - ) - } else { - self.attach_with_options( - interface, + options, + } => self.do_netlink_attach(if_index, attach_type, options, true), + SchedClassifierAttachment::Tcx { attach_type, - TcAttachOptions::Netlink(NlOptions::default()), - ) + link_order, + } => self.do_bpf_link_attach( + if_index, + attach_type.bpf_attach_type(), + &link_order, + Some(BpfLinkCreateArgs::Tcx(&link_order.link_ref)), + ), + SchedClassifierAttachment::Netkit { + attach_type, + link_order, + } => self.do_bpf_link_attach( + if_index, + attach_type.bpf_attach_type(), + &link_order, + Some(BpfLinkCreateArgs::Netkit(&link_order.link_ref)), + ), } } - /// Attaches the program to the given `interface` with options defined in [`TcAttachOptions`]. - /// - /// The returned value can be used to detach, see [`SchedClassifier::detach`]. - /// - /// # Link Pinning (TCX mode, kernel >= 6.6) - /// - /// Links can be pinned to bpffs for atomic replacement across process restarts. - /// - /// ```no_run - /// # use std::{io, path::Path}; - /// - /// # use aya::{ - /// # programs::{ - /// # LinkOrder, SchedClassifier, TcAttachType, - /// # links::{FdLink, LinkError, PinnedLink}, - /// # tc::TcAttachOptions, - /// # }, - /// # sys::SyscallError, - /// # }; - /// - /// # let mut bpf = aya::Ebpf::load(&[])?; - /// # let prog: &mut SchedClassifier = bpf.program_mut("prog").unwrap().try_into()?; - /// # prog.load()?; - /// let pin_path = "/sys/fs/bpf/my_link"; - /// - /// let link_id = match PinnedLink::from_pin(pin_path) { - /// Ok(old) => { - /// let link = FdLink::from(old).try_into()?; - /// prog.attach_to_link(link)? - /// } - /// Err(LinkError::SyscallError(SyscallError { io_error, .. })) - /// if io_error.kind() == io::ErrorKind::NotFound => - /// { - /// prog.attach_with_options( - /// "eth0", - /// TcAttachType::Ingress, - /// TcAttachOptions::TcxOrder(LinkOrder::default()), - /// )? - /// } - /// Err(e) => return Err(e.into()), - /// }; - /// - /// let link = prog.take_link(link_id)?; - /// let fd_link: FdLink = link.try_into()?; - /// fd_link.pin(pin_path)?; - /// # Ok::<(), Box>(()) - /// ``` - /// - /// # 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`]. - pub fn attach_with_options( - &mut self, - interface: &str, - attach_type: TcAttachType, - options: TcAttachOptions, - ) -> Result { - let if_index = ifindex_from_ifname(interface).map_err(TcError::IoError)?; - self.do_attach(if_index, attach_type, options, true) - } - /// Atomically replaces the program referenced by the provided link. /// /// Ownership of the link will transfer to this program. @@ -346,78 +418,84 @@ impl SchedClassifier { priority, handle, classid, - }) => self.do_attach( + }) => self.do_netlink_attach( if_index, attach_type, - TcAttachOptions::Netlink(NlOptions { + NlOptions { priority, handle, classid, - }), + }, false, ), } } - fn do_attach( + fn do_bpf_link_attach( &mut self, if_index: u32, - attach_type: TcAttachType, - options: TcAttachOptions, - create: bool, + attach_type: bpf_attach_type, + link_order: &LinkOrder, + bpf_link_create_args: Option>, ) -> Result { 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 as i32, - &attach_type, - prog_fd, - &name, - options.priority, - options.handle, - options.classid, - create, - ) - } - .map_err(TcError::NetlinkError)?; + let link_fd = bpf_link_create( + prog_fd, + LinkTarget::IfIndex(if_index), + attach_type, + link_order.flags.bits(), + bpf_link_create_args, + ) + .map_err(|io_error| SyscallError { + call: "bpf_mprog_attach", + io_error, + })?; + + self.data + .links + .insert(SchedClassifierLink::new(TcLinkInner::Fd(FdLink::new( + link_fd, + )))) + } - self.data - .links - .insert(SchedClassifierLink::new(TcLinkInner::NlLink(NlLink { - if_index, - attach_type, - priority, - handle, - classid: options.classid, - }))) - } - TcAttachOptions::TcxOrder(options) => { - let link_fd = bpf_link_create( - prog_fd, - LinkTarget::IfIndex(if_index), - attach_type.tcx_attach_type()?, - options.flags.bits(), - Some(BpfLinkCreateArgs::Tcx(&options.link_ref)), - ) - .map_err(|io_error| SyscallError { - call: "bpf_mprog_attach", - io_error, - })?; + fn do_netlink_attach( + &mut self, + if_index: u32, + attach_type: TcAttachType, + options: NlOptions, + create: bool, + ) -> Result { + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); - self.data - .links - .insert(SchedClassifierLink::new(TcLinkInner::Fd(FdLink::new( - link_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 as i32, + &attach_type, + prog_fd, + &name, + options.priority, + options.handle, + options.classid, + create, + ) } + .map_err(TcError::NetlinkError)?; + + self.data + .links + .insert(SchedClassifierLink::new(TcLinkInner::NlLink(NlLink { + if_index, + attach_type, + priority, + handle, + classid: options.classid, + }))) } /// Creates a program from a pinned entry on a bpffs. @@ -436,24 +514,52 @@ impl SchedClassifier { /// # Example /// /// ```no_run - /// # use aya::programs::tc::{TcAttachType, SchedClassifier}; + /// # use aya::programs::tc::{TcxAttachType, SchedClassifier}; /// # #[derive(Debug, thiserror::Error)] /// # enum Error { /// # #[error(transparent)] /// # Program(#[from] aya::programs::ProgramError), /// # } - /// let (revision, programs) = SchedClassifier::query_tcx("eth0", TcAttachType::Ingress)?; + /// let (revision, programs) = SchedClassifier::query_tcx("eth0", TcxAttachType::Ingress)?; /// # Ok::<(), Error>(()) /// ``` pub fn query_tcx( interface: &str, - attach_type: TcAttachType, + attach_type: TcxAttachType, + ) -> Result<(u64, Vec), ProgramError> { + Self::query_bpf_links(interface, attach_type.bpf_attach_type()) + } + + /// Queries a given interface for attached Netkit programs. + /// + /// # Example + /// + /// ```no_run + /// # use aya::programs::tc::{NetkitAttachType, SchedClassifier}; + /// # #[derive(Debug, thiserror::Error)] + /// # enum Error { + /// # #[error(transparent)] + /// # Program(#[from] aya::programs::ProgramError), + /// # } + /// let (revision, programs) = SchedClassifier::query_netkit("nk0", NetkitAttachType::Primary)?; + /// # Ok::<(), Error>(()) + /// ``` + pub fn query_netkit( + interface: &str, + attach_type: NetkitAttachType, + ) -> Result<(u64, Vec), ProgramError> { + Self::query_bpf_links(interface, attach_type.bpf_attach_type()) + } + + fn query_bpf_links( + interface: &str, + attach_type: bpf_attach_type, ) -> Result<(u64, Vec), ProgramError> { let if_index = ifindex_from_ifname(interface).map_err(TcError::IoError)?; let (revision, prog_ids) = query( ProgQueryTarget::IfIndex(if_index), - attach_type.tcx_attach_type()?, + attach_type, 0, &mut None, )?; @@ -551,11 +657,24 @@ impl<'a> TryFrom<&'a SchedClassifierLink> for &'a FdLink { } impl_try_into_fdlink!(SchedClassifierLink, TcLinkInner); -impl_try_from_fdlink!( - SchedClassifierLink, - TcLinkInner, - bpf_link_type::BPF_LINK_TYPE_TCX -); + +impl TryFrom for SchedClassifierLink { + type Error = LinkError; + + fn try_from(fd_link: FdLink) -> Result { + let info = crate::sys::bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; + + match info.type_ { + link_type + if link_type == bpf_link_type::BPF_LINK_TYPE_TCX as u32 + || link_type == bpf_link_type::BPF_LINK_TYPE_NETKIT as u32 => + { + Ok(Self::new(TcLinkInner::Fd(fd_link))) + } + _ => Err(LinkError::InvalidLink), + } + } +} define_link_wrapper!( SchedClassifierLink, @@ -653,7 +772,7 @@ impl SchedClassifierLink { } } -/// Add the `clasct` qdisc to the given interface. +/// Add the `clsact` qdisc to the given interface. /// /// The `clsact` qdisc must be added to an interface before [`SchedClassifier`] /// programs can be attached. diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 24ea0431a..14ee1c3bd 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -430,6 +430,8 @@ pub(crate) enum BpfLinkCreateArgs<'a> { PerfEvent { bpf_cookie: u64 }, // since kernel 6.6 Tcx(&'a LinkRef), + // since kernel 6.7 + Netkit(&'a LinkRef), } // since kernel 5.7 @@ -487,6 +489,25 @@ pub(crate) fn bpf_link_create( ); }, }, + BpfLinkCreateArgs::Netkit(link_ref) => match link_ref { + LinkRef::Fd(fd) => { + attr.link_create + .__bindgen_anon_3 + .netkit + .__bindgen_anon_1 + .relative_fd = fd.to_owned() as u32; + } + LinkRef::Id(id) => unsafe { + id.clone_into( + &mut attr + .link_create + .__bindgen_anon_3 + .netkit + .__bindgen_anon_1 + .relative_id, + ); + }, + }, } } diff --git a/test/integration-test/src/tests.rs b/test/integration-test/src/tests.rs index 88355697d..179c70c7e 100644 --- a/test/integration-test/src/tests.rs +++ b/test/integration-test/src/tests.rs @@ -26,6 +26,7 @@ mod lpm_trie; mod lsm; mod map_pin; mod maps_disjoint; +mod netkit; mod per_cpu_array; mod perf_event_array; mod perf_event_bp; diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 86fa92047..9144d5a56 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -8,13 +8,13 @@ use aya::{ maps::{Array, RingBuf}, pin::PinError, programs::{ - FlowDissector, KProbe, LinkOrder, ProbeKind, Program, ProgramError, SchedClassifier, - TcAttachType, TracePoint, UProbe, Xdp, XdpMode, + FlowDissector, KProbe, LinkOrder, NetkitAttachType, ProbeKind, Program, ProgramError, + SchedClassifier, SchedClassifierAttachment, TcxAttachType, TracePoint, UProbe, Xdp, + XdpMode, flow_dissector::{FlowDissectorLink, FlowDissectorLinkId}, kprobe::{KProbeLink, KProbeLinkId}, links::{FdLink, LinkError, PinnedLink}, loaded_links, loaded_programs, - tc::TcAttachOptions, trace_point::{TracePointLink, TracePointLinkId}, uprobe::{UProbeLink, UProbeLinkId, UProbeScope}, xdp::{XdpLink, XdpLinkId}, @@ -24,6 +24,8 @@ use aya::{ use aya_obj::programs::XdpAttachType; use test_case::test_case; +use crate::utils::NetNsGuard; + const MAX_RETRIES: usize = 100; pub(crate) const RETRY_DURATION: Duration = Duration::from_millis(10); @@ -447,7 +449,6 @@ fn pin_tcx_link() { return; } - use crate::utils::NetNsGuard; let _netns = NetNsGuard::new(); let program_name = "tcx_next"; @@ -457,10 +458,12 @@ fn pin_tcx_link() { prog.load().unwrap(); let link_id = prog - .attach_with_options( + .attach( "lo", - TcAttachType::Ingress, - TcAttachOptions::TcxOrder(LinkOrder::default()), + SchedClassifierAttachment::Tcx { + attach_type: TcxAttachType::Ingress, + link_order: LinkOrder::default(), + }, ) .unwrap(); let link = prog.take_link(link_id).unwrap(); @@ -490,6 +493,62 @@ fn pin_tcx_link() { assert_unloaded(program_name); } +#[test_log::test] +fn pin_netkit_link() { + let kernel_version = KernelVersion::current().unwrap(); + if kernel_version < KernelVersion::new(6, 7, 0) { + eprintln!("skipping pin_netkit_link test on kernel {kernel_version:?}"); + return; + } + + use crate::utils::create_netkit_link; + let _netns = NetNsGuard::new(); + if let Err(err) = create_netkit_link("nk-aya-0", "nk-aya-1") { + eprintln!("skipping pin_netkit_link test: {err}"); + return; + } + + let program_name = "tcx_next"; + let pin_path = "/sys/fs/bpf/aya-netkit-test-nk0"; + let mut bpf = Ebpf::load(crate::TCX).unwrap(); + let prog: &mut SchedClassifier = bpf.program_mut(program_name).unwrap().try_into().unwrap(); + prog.load().unwrap(); + + let link_id = prog + .attach( + "nk0", + SchedClassifierAttachment::Netkit { + attach_type: NetkitAttachType::Primary, + link_order: LinkOrder::default(), + }, + ) + .unwrap(); + let link = prog.take_link(link_id).unwrap(); + assert_loaded(program_name); + + let fd_link: FdLink = link.try_into().unwrap(); + fd_link.pin(pin_path).unwrap(); + + // Because of the pin, the program is still attached. + prog.unload().unwrap(); + assert_loaded(program_name); + + // Load a new program and atomically replace the old one using attach_to_link. + let mut bpf = Ebpf::load(crate::TCX).unwrap(); + let prog: &mut SchedClassifier = bpf.program_mut(program_name).unwrap().try_into().unwrap(); + prog.load().unwrap(); + + let old_link = PinnedLink::from_pin(pin_path).unwrap(); + let link = FdLink::from(old_link).try_into().unwrap(); + let _link_id = prog.attach_to_link(link).unwrap(); + + assert_loaded(program_name); + + remove_file(pin_path).unwrap(); + drop(bpf); + assert_unloaded(program_name); +} + trait PinProgramOps { fn pin>(&mut self, path: P) -> Result<(), PinError>; fn unpin(&mut self) -> Result<(), std::io::Error>; diff --git a/test/integration-test/src/tests/netkit.rs b/test/integration-test/src/tests/netkit.rs new file mode 100644 index 000000000..9ccd6a039 --- /dev/null +++ b/test/integration-test/src/tests/netkit.rs @@ -0,0 +1,108 @@ +use aya::{ + Ebpf, + programs::{ + LinkOrder, NetkitAttachType, ProgramId, SchedClassifier, tc::SchedClassifierAttachment, + }, + util::KernelVersion, +}; + +use crate::utils::{NetNsGuard, create_netkit_link}; + +#[test_log::test] +fn netkit() { + let kernel_version = KernelVersion::current().unwrap(); + if kernel_version < KernelVersion::new(6, 7, 0) { + eprintln!("skipping netkit_attach test on kernel {kernel_version:?}"); + return; + } + let primary = "nk-aya-0"; + let peer = "nk-aya-1"; + + let _netns = NetNsGuard::new(); + if let Err(err) = create_netkit_link(primary, peer) { + eprintln!("skipping netkit_attach test: {err}"); + return; + } + + 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( + primary, + SchedClassifierAttachment::Netkit { + attach_type: NetkitAttachType::Primary, + link_order: $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( + primary, + SchedClassifierAttachment::Netkit { + attach_type: NetkitAttachType::Primary, + link_order: $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::>(); + + let (revision, got_order) = + SchedClassifier::query_netkit(primary, NetkitAttachType::Primary).unwrap(); + assert_eq!(revision, (expected_order.len() + 1) as u64); + assert_eq!( + got_order + .iter() + .map(aya::programs::ProgramInfo::id) + .collect::>(), + expected_order + ); +} diff --git a/test/integration-test/src/tests/tc_netlink.rs b/test/integration-test/src/tests/tc_netlink.rs index 2f367ad75..60c156829 100644 --- a/test/integration-test/src/tests/tc_netlink.rs +++ b/test/integration-test/src/tests/tc_netlink.rs @@ -2,7 +2,7 @@ use aya::{ Ebpf, programs::{ SchedClassifier, TcAttachType, - tc::{NlOptions, TcAttachOptions, TcHandle, qdisc_add_clsact}, + tc::{NlOptions, SchedClassifierAttachment, TcHandle, qdisc_add_clsact}, }, util::KernelVersion, }; @@ -54,13 +54,15 @@ fn netlink_attach_to_link_preserves_classid() { let classid = TcHandle::new(1, 1); let link_id = prog - .attach_with_options( + .attach( "lo", - TcAttachType::Ingress, - TcAttachOptions::Netlink(NlOptions { - classid: Some(classid), - ..Default::default() - }), + SchedClassifierAttachment::Tc { + attach_type: TcAttachType::Ingress, + options: NlOptions { + classid: Some(classid), + ..Default::default() + }, + }, ) .unwrap(); @@ -89,10 +91,12 @@ fn netlink_attach_auto_assigns_handle() { prog.load().unwrap(); let link_id = prog - .attach_with_options( + .attach( "lo", - TcAttachType::Ingress, - TcAttachOptions::Netlink(NlOptions::default()), + SchedClassifierAttachment::Tc { + attach_type: TcAttachType::Ingress, + options: NlOptions::default(), + }, ) .unwrap(); @@ -118,13 +122,15 @@ fn netlink_attach_preserves_explicit_handle() { let handle = TcHandle::new(1, 0xfffe); let link_id = prog - .attach_with_options( + .attach( "lo", - TcAttachType::Ingress, - TcAttachOptions::Netlink(NlOptions { - handle, - ..Default::default() - }), + SchedClassifierAttachment::Tc { + attach_type: TcAttachType::Ingress, + options: NlOptions { + handle, + ..Default::default() + }, + }, ) .unwrap(); diff --git a/test/integration-test/src/tests/tcx.rs b/test/integration-test/src/tests/tcx.rs index 774a9b80a..a65c99ae4 100644 --- a/test/integration-test/src/tests/tcx.rs +++ b/test/integration-test/src/tests/tcx.rs @@ -1,6 +1,8 @@ use aya::{ Ebpf, - programs::{LinkOrder, ProgramId, SchedClassifier, TcAttachType, tc::TcAttachOptions}, + programs::{ + LinkOrder, ProgramId, SchedClassifier, TcxAttachType, tc::SchedClassifierAttachment, + }, util::KernelVersion, }; @@ -37,20 +39,24 @@ fn tcx() { ($program_name:ident, $link_order:expr) => { attach_program_with_link_order_inner!($program_name, $link_order); $program_name - .attach_with_options( + .attach( "lo", - TcAttachType::Ingress, - TcAttachOptions::TcxOrder($link_order), + SchedClassifierAttachment::Tcx { + attach_type: TcxAttachType::Ingress, + link_order: $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( + .attach( "lo", - TcAttachType::Ingress, - TcAttachOptions::TcxOrder($link_order), + SchedClassifierAttachment::Tcx { + attach_type: TcxAttachType::Ingress, + link_order: $link_order, + }, ) .unwrap(); }; @@ -92,7 +98,7 @@ fn tcx() { .map(|program| program.info().unwrap().id()) .collect::>(); - let (revision, got_order) = SchedClassifier::query_tcx("lo", TcAttachType::Ingress).unwrap(); + let (revision, got_order) = SchedClassifier::query_tcx("lo", TcxAttachType::Ingress).unwrap(); assert_eq!(revision, (expected_order.len() + 1) as u64); assert_eq!( got_order diff --git a/test/integration-test/src/utils.rs b/test/integration-test/src/utils.rs index c0efe3765..60e81cb06 100644 --- a/test/integration-test/src/utils.rs +++ b/test/integration-test/src/utils.rs @@ -8,7 +8,7 @@ use std::{ io::{self, Write as _}, os::fd::{AsFd, BorrowedFd}, path::Path, - process, + process::{self, Command}, sync::atomic::{AtomicU64, Ordering}, }; @@ -282,3 +282,35 @@ macro_rules! kernel_assert_eq { } pub(crate) use kernel_assert_eq; + +pub(crate) fn ifindex(if_name: &str) -> io::Result { + let if_name = + CString::new(if_name).map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?; + let idx = unsafe { if_nametoindex(if_name.as_ptr()) }; + if idx == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(idx) + } +} + +pub(crate) fn create_netkit_link(primary: &str, peer: &str) -> io::Result<()> { + let output = Command::new("ip") + .args([ + "link", "add", "name", primary, "type", "netkit", "peer", "name", peer, + ]) + .output()?; + if !output.status.success() { + return Err(io::Error::other(format!( + "`ip link add name {primary} type netkit peer name {peer}` failed: {}", + String::from_utf8_lossy(&output.stderr) + ))); + } + + for if_name in [primary, peer] { + let idx = ifindex(if_name)?; + unsafe { netlink_set_link_up(idx as i32) }.map_err(io::Error::other)?; + } + + Ok(()) +} diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 17b4f1318..fe01df3aa 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -4519,18 +4519,44 @@ impl core::marker::UnsafeUnpin for aya::programs::socket_filter::SocketFilterLin impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::socket_filter::SocketFilterLinkId impl core::panic::unwind_safe::UnwindSafe for aya::programs::socket_filter::SocketFilterLinkId 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::marker::UnsafeUnpin 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 +pub enum aya::programs::tc::NetkitAttachType +pub aya::programs::tc::NetkitAttachType::Peer +pub aya::programs::tc::NetkitAttachType::Primary +impl core::clone::Clone for aya::programs::tc::NetkitAttachType +pub fn aya::programs::tc::NetkitAttachType::clone(&self) -> aya::programs::tc::NetkitAttachType +impl core::cmp::Eq for aya::programs::tc::NetkitAttachType +impl core::cmp::PartialEq for aya::programs::tc::NetkitAttachType +pub fn aya::programs::tc::NetkitAttachType::eq(&self, other: &aya::programs::tc::NetkitAttachType) -> bool +impl core::fmt::Debug for aya::programs::tc::NetkitAttachType +pub fn aya::programs::tc::NetkitAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for aya::programs::tc::NetkitAttachType +pub fn aya::programs::tc::NetkitAttachType::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +impl core::marker::Copy for aya::programs::tc::NetkitAttachType +impl core::marker::StructuralPartialEq for aya::programs::tc::NetkitAttachType +impl core::marker::Freeze for aya::programs::tc::NetkitAttachType +impl core::marker::Send for aya::programs::tc::NetkitAttachType +impl core::marker::Sync for aya::programs::tc::NetkitAttachType +impl core::marker::Unpin for aya::programs::tc::NetkitAttachType +impl core::marker::UnsafeUnpin for aya::programs::tc::NetkitAttachType +impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::NetkitAttachType +impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::NetkitAttachType +pub enum aya::programs::tc::SchedClassifierAttachment +pub aya::programs::tc::SchedClassifierAttachment::Netkit +pub aya::programs::tc::SchedClassifierAttachment::Netkit::attach_type: aya::programs::tc::NetkitAttachType +pub aya::programs::tc::SchedClassifierAttachment::Netkit::link_order: aya::programs::links::LinkOrder +pub aya::programs::tc::SchedClassifierAttachment::Tc +pub aya::programs::tc::SchedClassifierAttachment::Tc::attach_type: aya::programs::tc::TcAttachType +pub aya::programs::tc::SchedClassifierAttachment::Tc::options: aya::programs::tc::NlOptions +pub aya::programs::tc::SchedClassifierAttachment::Tcx +pub aya::programs::tc::SchedClassifierAttachment::Tcx::attach_type: aya::programs::tc::TcxAttachType +pub aya::programs::tc::SchedClassifierAttachment::Tcx::link_order: aya::programs::links::LinkOrder +impl core::marker::Freeze for aya::programs::tc::SchedClassifierAttachment +impl core::marker::Send for aya::programs::tc::SchedClassifierAttachment +impl core::marker::Sync for aya::programs::tc::SchedClassifierAttachment +impl core::marker::Unpin for aya::programs::tc::SchedClassifierAttachment +impl core::marker::UnsafeUnpin for aya::programs::tc::SchedClassifierAttachment +impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::SchedClassifierAttachment +impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::SchedClassifierAttachment pub enum aya::programs::tc::TcAttachType pub aya::programs::tc::TcAttachType::Custom(u32) pub aya::programs::tc::TcAttachType::Egress @@ -4556,7 +4582,6 @@ impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcAttachType 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::IoError(std::io::error::Error) pub aya::programs::tc::TcError::NetlinkError(aya::sys::netlink::NetlinkError) pub aya::programs::tc::TcError::NulError(alloc::ffi::c_str::NulError) @@ -4579,6 +4604,27 @@ impl core::marker::Unpin for aya::programs::tc::TcError impl core::marker::UnsafeUnpin for aya::programs::tc::TcError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcError +pub enum aya::programs::tc::TcxAttachType +pub aya::programs::tc::TcxAttachType::Egress +pub aya::programs::tc::TcxAttachType::Ingress +impl core::clone::Clone for aya::programs::tc::TcxAttachType +pub fn aya::programs::tc::TcxAttachType::clone(&self) -> aya::programs::tc::TcxAttachType +impl core::cmp::Eq for aya::programs::tc::TcxAttachType +impl core::cmp::PartialEq for aya::programs::tc::TcxAttachType +pub fn aya::programs::tc::TcxAttachType::eq(&self, other: &aya::programs::tc::TcxAttachType) -> bool +impl core::fmt::Debug for aya::programs::tc::TcxAttachType +pub fn aya::programs::tc::TcxAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for aya::programs::tc::TcxAttachType +pub fn aya::programs::tc::TcxAttachType::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +impl core::marker::Copy for aya::programs::tc::TcxAttachType +impl core::marker::StructuralPartialEq for aya::programs::tc::TcxAttachType +impl core::marker::Freeze for aya::programs::tc::TcxAttachType +impl core::marker::Send for aya::programs::tc::TcxAttachType +impl core::marker::Sync for aya::programs::tc::TcxAttachType +impl core::marker::Unpin for aya::programs::tc::TcxAttachType +impl core::marker::UnsafeUnpin for aya::programs::tc::TcxAttachType +impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcxAttachType +impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcxAttachType pub struct aya::programs::tc::NlOptions pub aya::programs::tc::NlOptions::classid: core::option::Option pub aya::programs::tc::NlOptions::handle: aya::programs::tc::TcHandle @@ -4603,12 +4649,12 @@ impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::NlOptions pub struct aya::programs::tc::SchedClassifier impl aya::programs::tc::SchedClassifier pub const aya::programs::tc::SchedClassifier::PROGRAM_TYPE: aya::programs::ProgramType -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(&mut self, interface: &str, attachment: aya::programs::tc::SchedClassifierAttachment) -> 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::TcAttachOptions) -> core::result::Result 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> -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::ProgramError> +pub fn aya::programs::tc::SchedClassifier::query_netkit(interface: &str, attach_type: aya::programs::tc::NetkitAttachType) -> core::result::Result<(u64, alloc::vec::Vec), aya::programs::ProgramError> +pub fn aya::programs::tc::SchedClassifier::query_tcx(interface: &str, attach_type: aya::programs::tc::TcxAttachType) -> core::result::Result<(u64, alloc::vec::Vec), aya::programs::ProgramError> impl aya::programs::tc::SchedClassifier 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::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result @@ -5307,6 +5353,27 @@ impl core::marker::Unpin for aya::programs::LsmAttachType impl core::marker::UnsafeUnpin for aya::programs::LsmAttachType impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::LsmAttachType impl core::panic::unwind_safe::UnwindSafe for aya::programs::LsmAttachType +pub enum aya::programs::NetkitAttachType +pub aya::programs::NetkitAttachType::Peer +pub aya::programs::NetkitAttachType::Primary +impl core::clone::Clone for aya::programs::tc::NetkitAttachType +pub fn aya::programs::tc::NetkitAttachType::clone(&self) -> aya::programs::tc::NetkitAttachType +impl core::cmp::Eq for aya::programs::tc::NetkitAttachType +impl core::cmp::PartialEq for aya::programs::tc::NetkitAttachType +pub fn aya::programs::tc::NetkitAttachType::eq(&self, other: &aya::programs::tc::NetkitAttachType) -> bool +impl core::fmt::Debug for aya::programs::tc::NetkitAttachType +pub fn aya::programs::tc::NetkitAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for aya::programs::tc::NetkitAttachType +pub fn aya::programs::tc::NetkitAttachType::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +impl core::marker::Copy for aya::programs::tc::NetkitAttachType +impl core::marker::StructuralPartialEq for aya::programs::tc::NetkitAttachType +impl core::marker::Freeze for aya::programs::tc::NetkitAttachType +impl core::marker::Send for aya::programs::tc::NetkitAttachType +impl core::marker::Sync for aya::programs::tc::NetkitAttachType +impl core::marker::Unpin for aya::programs::tc::NetkitAttachType +impl core::marker::UnsafeUnpin for aya::programs::tc::NetkitAttachType +impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::NetkitAttachType +impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::NetkitAttachType pub enum aya::programs::ProbeKind pub aya::programs::ProbeKind::Entry pub aya::programs::ProbeKind::Return @@ -5651,6 +5718,23 @@ impl core::marker::Unpin for aya::programs::ProgramType impl core::marker::UnsafeUnpin for aya::programs::ProgramType impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::ProgramType impl core::panic::unwind_safe::UnwindSafe for aya::programs::ProgramType +pub enum aya::programs::SchedClassifierAttachment +pub aya::programs::SchedClassifierAttachment::Netkit +pub aya::programs::SchedClassifierAttachment::Netkit::attach_type: aya::programs::tc::NetkitAttachType +pub aya::programs::SchedClassifierAttachment::Netkit::link_order: aya::programs::links::LinkOrder +pub aya::programs::SchedClassifierAttachment::Tc +pub aya::programs::SchedClassifierAttachment::Tc::attach_type: aya::programs::tc::TcAttachType +pub aya::programs::SchedClassifierAttachment::Tc::options: aya::programs::tc::NlOptions +pub aya::programs::SchedClassifierAttachment::Tcx +pub aya::programs::SchedClassifierAttachment::Tcx::attach_type: aya::programs::tc::TcxAttachType +pub aya::programs::SchedClassifierAttachment::Tcx::link_order: aya::programs::links::LinkOrder +impl core::marker::Freeze for aya::programs::tc::SchedClassifierAttachment +impl core::marker::Send for aya::programs::tc::SchedClassifierAttachment +impl core::marker::Sync for aya::programs::tc::SchedClassifierAttachment +impl core::marker::Unpin for aya::programs::tc::SchedClassifierAttachment +impl core::marker::UnsafeUnpin for aya::programs::tc::SchedClassifierAttachment +impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::SchedClassifierAttachment +impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::SchedClassifierAttachment pub enum aya::programs::SkReuseportError pub aya::programs::SkReuseportError::SetsockoptError pub aya::programs::SkReuseportError::SetsockoptError::io_error: std::io::error::Error @@ -5713,7 +5797,6 @@ impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcAttachType 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::IoError(std::io::error::Error) pub aya::programs::TcError::NetlinkError(aya::sys::netlink::NetlinkError) pub aya::programs::TcError::NulError(alloc::ffi::c_str::NulError) @@ -5736,6 +5819,27 @@ impl core::marker::Unpin for aya::programs::tc::TcError impl core::marker::UnsafeUnpin for aya::programs::tc::TcError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcError +pub enum aya::programs::TcxAttachType +pub aya::programs::TcxAttachType::Egress +pub aya::programs::TcxAttachType::Ingress +impl core::clone::Clone for aya::programs::tc::TcxAttachType +pub fn aya::programs::tc::TcxAttachType::clone(&self) -> aya::programs::tc::TcxAttachType +impl core::cmp::Eq for aya::programs::tc::TcxAttachType +impl core::cmp::PartialEq for aya::programs::tc::TcxAttachType +pub fn aya::programs::tc::TcxAttachType::eq(&self, other: &aya::programs::tc::TcxAttachType) -> bool +impl core::fmt::Debug for aya::programs::tc::TcxAttachType +pub fn aya::programs::tc::TcxAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::hash::Hash for aya::programs::tc::TcxAttachType +pub fn aya::programs::tc::TcxAttachType::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +impl core::marker::Copy for aya::programs::tc::TcxAttachType +impl core::marker::StructuralPartialEq for aya::programs::tc::TcxAttachType +impl core::marker::Freeze for aya::programs::tc::TcxAttachType +impl core::marker::Send for aya::programs::tc::TcxAttachType +impl core::marker::Sync for aya::programs::tc::TcxAttachType +impl core::marker::Unpin for aya::programs::tc::TcxAttachType +impl core::marker::UnsafeUnpin for aya::programs::tc::TcxAttachType +impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcxAttachType +impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcxAttachType pub enum aya::programs::TracePointError pub aya::programs::TracePointError::FileError pub aya::programs::TracePointError::FileError::filename: std::path::PathBuf @@ -6615,12 +6719,12 @@ impl core::panic::unwind_safe::UnwindSafe for aya::programs::RawTracePointTestRu pub struct aya::programs::SchedClassifier impl aya::programs::tc::SchedClassifier pub const aya::programs::tc::SchedClassifier::PROGRAM_TYPE: aya::programs::ProgramType -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(&mut self, interface: &str, attachment: aya::programs::tc::SchedClassifierAttachment) -> 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::TcAttachOptions) -> core::result::Result 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> -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::ProgramError> +pub fn aya::programs::tc::SchedClassifier::query_netkit(interface: &str, attach_type: aya::programs::tc::NetkitAttachType) -> core::result::Result<(u64, alloc::vec::Vec), aya::programs::ProgramError> +pub fn aya::programs::tc::SchedClassifier::query_tcx(interface: &str, attach_type: aya::programs::tc::TcxAttachType) -> core::result::Result<(u64, alloc::vec::Vec), aya::programs::ProgramError> impl aya::programs::tc::SchedClassifier 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::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result