|
|
|
|
@ -6,11 +6,13 @@ use aya::{
|
|
|
|
|
maps::Array,
|
|
|
|
|
pin::PinError,
|
|
|
|
|
programs::{
|
|
|
|
|
FlowDissector, KProbe, ProbeKind, Program, ProgramError, TracePoint, UProbe, Xdp, XdpFlags,
|
|
|
|
|
FlowDissector, KProbe, LinkOrder, ProbeKind, Program, ProgramError, SchedClassifier,
|
|
|
|
|
TcAttachType, TracePoint, UProbe, Xdp, XdpFlags,
|
|
|
|
|
flow_dissector::{FlowDissectorLink, FlowDissectorLinkId},
|
|
|
|
|
kprobe::{KProbeLink, KProbeLinkId},
|
|
|
|
|
links::{FdLink, LinkError, PinnedLink},
|
|
|
|
|
loaded_links, loaded_programs,
|
|
|
|
|
tc::TcAttachOptions,
|
|
|
|
|
trace_point::{TracePointLink, TracePointLinkId},
|
|
|
|
|
uprobe::{UProbeLink, UProbeLinkId},
|
|
|
|
|
xdp::{XdpLink, XdpLinkId},
|
|
|
|
|
@ -394,6 +396,58 @@ fn pin_link() {
|
|
|
|
|
assert_unloaded(program_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test_log::test]
|
|
|
|
|
fn pin_tcx_link() {
|
|
|
|
|
// TCX links require kernel >= 6.6
|
|
|
|
|
let kernel_version = KernelVersion::current().unwrap();
|
|
|
|
|
if kernel_version < KernelVersion::new(6, 6, 0) {
|
|
|
|
|
eprintln!("skipping pin_tcx_link test on kernel {kernel_version:?}");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use crate::utils::NetNsGuard;
|
|
|
|
|
let _netns = NetNsGuard::new();
|
|
|
|
|
|
|
|
|
|
let program_name = "tcx_next";
|
|
|
|
|
let pin_path = "/sys/fs/bpf/aya-tcx-test-lo";
|
|
|
|
|
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_with_options(
|
|
|
|
|
"lo",
|
|
|
|
|
TcAttachType::Ingress,
|
|
|
|
|
TcAttachOptions::TcxOrder(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);
|
|
|
|
|
|
|
|
|
|
// Clean up: remove the stale pin file and drop the bpf instance (which drops the program and link)
|
|
|
|
|
remove_file(pin_path).unwrap();
|
|
|
|
|
drop(bpf);
|
|
|
|
|
assert_unloaded(program_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trait PinProgramOps {
|
|
|
|
|
fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), PinError>;
|
|
|
|
|
fn unpin(&mut self) -> Result<(), std::io::Error>;
|
|
|
|
|
|