diff --git a/test/integration-ebpf/src/tcx.rs b/test/integration-ebpf/src/tcx.rs index 324a1788..8d537d52 100644 --- a/test/integration-ebpf/src/tcx.rs +++ b/test/integration-ebpf/src/tcx.rs @@ -1,74 +1,22 @@ #![no_std] #![no_main] -use core::mem; - use aya_ebpf::{ bindings::tcx_action_base::{TCX_NEXT, TCX_PASS}, macros::classifier, programs::TcContext, }; -use aya_log_ebpf::info; -use network_types::{ - eth::{EthHdr, EtherType}, - ip::{IpProto, Ipv4Hdr}, - udp::UdpHdr, -}; - -#[no_mangle] -static ORDER: i32 = 0; - -// Gives us raw pointers to a specific offset in the packet -unsafe fn ptr_at(ctx: &TcContext, offset: usize) -> Result<*mut T, i64> { - let start = ctx.data(); - let end = ctx.data_end(); - let len = mem::size_of::(); - - if start + offset + len > end { - return Err(TCX_PASS.into()); - } - Ok((start + offset) as *mut T) -} #[classifier] -pub fn tcx_order(ctx: TcContext) -> i32 { +pub fn tcx_next(ctx: TcContext) -> i32 { match try_tcxtest(ctx) { Ok(ret) => ret, - Err(_ret) => TCX_PASS, + Err(_) => TCX_PASS, } } -fn try_tcxtest(ctx: TcContext) -> Result { - let eth_hdr: *const EthHdr = unsafe { ptr_at(&ctx, 0) }?; - let order = unsafe { core::ptr::read_volatile(&ORDER) }; - match unsafe { *eth_hdr }.ether_type { - EtherType::Ipv4 => { - let ipv4_hdr: *const Ipv4Hdr = unsafe { ptr_at(&ctx, EthHdr::LEN)? }; - let saddr = u32::from_be(unsafe { (*ipv4_hdr).src_addr }); - let daddr = u32::from_be(unsafe { (*ipv4_hdr).dst_addr }); - match unsafe { (*ipv4_hdr).proto } { - IpProto::Udp => { - let udphdr: *const UdpHdr = - unsafe { ptr_at(&ctx, EthHdr::LEN + Ipv4Hdr::LEN) }?; - let dport = u16::from_be(unsafe { (*udphdr).dest }); - let sport = u16::from_be(unsafe { (*udphdr).source }); - info!( - &ctx, - "order: {}, cookie: ({:i}, {:i}, {}, {})", - order, - daddr, - saddr, - dport, - sport - ); - - Ok(TCX_NEXT) - } - _ => Ok(TCX_PASS), - } - } - _ => Ok(TCX_PASS), - } +fn try_tcxtest(_ctx: TcContext) -> Result { + Ok(TCX_NEXT) } #[cfg(not(test))] diff --git a/test/integration-test/src/tests/tcx.rs b/test/integration-test/src/tests/tcx.rs index ad21d2e9..7aad2325 100644 --- a/test/integration-test/src/tests/tcx.rs +++ b/test/integration-test/src/tests/tcx.rs @@ -1,14 +1,17 @@ use aya::{ - programs::{tc::TcAttachOptions, LinkOrder, SchedClassifier, TcAttachType}, + programs::{ + tc::{SchedClassifierLink, TcAttachOptions}, + Link, LinkOrder, ProgramId, SchedClassifier, TcAttachType, + }, util::KernelVersion, - EbpfLoader, + Ebpf, EbpfLoader, }; use test_log::test; use crate::utils::NetNsGuard; #[test(tokio::test)] -async fn tcx_attach() { +async fn tcx() { let kernel_version = KernelVersion::current().unwrap(); if kernel_version < KernelVersion::new(6, 6, 0) { eprintln!("skipping tcx_attach test on kernel {kernel_version:?}"); @@ -17,77 +20,127 @@ async fn tcx_attach() { let _netns = NetNsGuard::new(); - let mut program0 = EbpfLoader::new() - .set_global("ORDER", &0, true) - .load(crate::TCX) - .unwrap(); - let mut program1 = EbpfLoader::new() - .set_global("ORDER", &1, true) - .load(crate::TCX) - .unwrap(); - let mut program2 = EbpfLoader::new() - .set_global("ORDER", &2, true) - .load(crate::TCX) - .unwrap(); - let mut program3 = EbpfLoader::new() - .set_global("ORDER", &3, true) - .load(crate::TCX) + // Create 9 programs for testing the 9 different LinkOrder constructors. + let mut programs: Vec = vec![]; + for _ in 0..9 { + let program = EbpfLoader::new().load(crate::TCX).unwrap(); + programs.push(program); + } + + let mut tcx_programs: Vec<&mut SchedClassifier> = vec![]; + for program in programs.iter_mut() { + let prog: &mut SchedClassifier = + program.program_mut("tcx_next").unwrap().try_into().unwrap(); + prog.load().unwrap(); + tcx_programs.push(prog); + } + + let mut tcx_links: Vec = vec![]; + + // Test LinkOrder::default() + // Should end up in position 4 at the end of the test. + let order = LinkOrder::default(); + let options = TcAttachOptions::TcxOrder(order); + let link_id = tcx_programs[0] + .attach_with_options("lo", TcAttachType::Ingress, options) .unwrap(); + let link = tcx_programs[0].take_link(link_id).unwrap(); + tcx_links.push(link); - let prog0: &mut SchedClassifier = program0 - .program_mut("tcx_order") - .unwrap() - .try_into() + // Test LinkOrder::first() + // Should end up in position 1 at the end of the test. + let order: LinkOrder = LinkOrder::first(); + let options = TcAttachOptions::TcxOrder(order); + let link_id = tcx_programs[1] + .attach_with_options("lo", TcAttachType::Ingress, options) .unwrap(); - prog0.load().unwrap(); + let link = tcx_programs[1].take_link(link_id).unwrap(); + tcx_links.push(link); - let prog1: &mut SchedClassifier = program1 - .program_mut("tcx_order") - .unwrap() - .try_into() + // Test LinkOrder::last() + // Should end up in position 7 at the end of the test. + let order: LinkOrder = LinkOrder::last(); + let options = TcAttachOptions::TcxOrder(order); + let link_id = tcx_programs[2] + .attach_with_options("lo", TcAttachType::Ingress, options) .unwrap(); - prog1.load().unwrap(); + let link = tcx_programs[2].take_link(link_id).unwrap(); + tcx_links.push(link); - let prog2: &mut SchedClassifier = program2 - .program_mut("tcx_order") - .unwrap() - .try_into() + // Test LinkOrder::before_link() + // Should end up in position 6 at the end of the test. + let order = LinkOrder::before_link(&tcx_links[2]).unwrap(); + let options = TcAttachOptions::TcxOrder(order); + let link_id = tcx_programs[3] + .attach_with_options("lo", TcAttachType::Ingress, options) .unwrap(); - prog2.load().unwrap(); + let link = tcx_programs[3].take_link(link_id).unwrap(); + tcx_links.push(link); - let prog3: &mut SchedClassifier = program3 - .program_mut("tcx_order") - .unwrap() - .try_into() + // Test LinkOrder::after_link() + // Should end up in position 8 at the end of the test. + let order = LinkOrder::after_link(&tcx_links[2]).unwrap(); + let options = TcAttachOptions::TcxOrder(order); + let link_id = tcx_programs[4] + .attach_with_options("lo", TcAttachType::Ingress, options) .unwrap(); - prog3.load().unwrap(); + let link = tcx_programs[4].take_link(link_id).unwrap(); + tcx_links.push(link); - // Test LinkOrder::last() - let order: LinkOrder = LinkOrder::last(); + // Test LinkOrder::before_program() + // Should end up in position 3 at the end of the test. + let order = LinkOrder::before_program(tcx_programs[0]).unwrap(); let options = TcAttachOptions::TcxOrder(order); - prog0 + let link_id = tcx_programs[5] .attach_with_options("lo", TcAttachType::Ingress, options) .unwrap(); + let link = tcx_programs[5].take_link(link_id).unwrap(); + tcx_links.push(link); // Test LinkOrder::after_program() - let order = LinkOrder::after_program(prog0).unwrap(); + // Should end up in position 5 at the end of the test. + let order = LinkOrder::after_program(tcx_programs[0]).unwrap(); let options = TcAttachOptions::TcxOrder(order); - let prog1_link_id = prog1 + let link_id = tcx_programs[6] .attach_with_options("lo", TcAttachType::Ingress, options) .unwrap(); + let link = tcx_programs[6].take_link(link_id).unwrap(); + tcx_links.push(link); - let prog1_link = prog1.take_link(prog1_link_id).unwrap(); - - // Test LinkOrder::after_link() - let order = LinkOrder::after_link(&prog1_link).unwrap(); + // Test LinkOrder::before_program_id() + // Should end up in position 0 at the end of the test. + let prog_1_id = unsafe { ProgramId::new(tcx_programs[1].info().unwrap().id()) }; + let order = LinkOrder::before_program_id(prog_1_id); let options = TcAttachOptions::TcxOrder(order); - prog2 + let link_id = tcx_programs[7] .attach_with_options("lo", TcAttachType::Ingress, options) .unwrap(); + let link = tcx_programs[7].take_link(link_id).unwrap(); + tcx_links.push(link); - // Test LinkOrder::last() - let options = TcAttachOptions::TcxOrder(LinkOrder::last()); - prog3 + // Test LinkOrder::after_program_id() + // Should end up in position 2 at the end of the test. + let prog_1_id = unsafe { ProgramId::new(tcx_programs[1].info().unwrap().id()) }; + let order = LinkOrder::after_program_id(prog_1_id); + let options = TcAttachOptions::TcxOrder(order); + let link_id = tcx_programs[8] .attach_with_options("lo", TcAttachType::Ingress, options) .unwrap(); + let link = tcx_programs[8].take_link(link_id).unwrap(); + tcx_links.push(link); + + // It as been manually verified that all the programs are attached in the + // correct order. + // TODO: Add code here to automatically verify the order after the API based + // on the BPF_PROG_QUERY syscall is implemented. + + // Detach all links + while let Some(link) = tcx_links.pop() { + link.detach().unwrap(); + } + + // Unload all programs + for program in tcx_programs { + program.unload().unwrap(); + } }