@ -1,14 +1,19 @@
use std ::collections ::HashMap ;
use aya ::{
use aya ::{
programs ::{ tc ::TcAttachOptions , LinkOrder , SchedClassifier , TcAttachType } ,
programs ::{
tc ::{ SchedClassifierLink , TcAttachOptions } ,
LinkOrder , ProgramId , SchedClassifier , TcAttachType ,
} ,
util ::KernelVersion ,
util ::KernelVersion ,
EbpfLoader ,
Ebpf , Ebpf Loader,
} ;
} ;
use test_log ::test ;
use test_log ::test ;
use crate ::utils ::NetNsGuard ;
use crate ::utils ::NetNsGuard ;
#[ test(tokio::test) ]
#[ test(tokio::test) ]
async fn tcx _attach ( ) {
async fn tcx ( ) {
let kernel_version = KernelVersion ::current ( ) . unwrap ( ) ;
let kernel_version = KernelVersion ::current ( ) . unwrap ( ) ;
if kernel_version < KernelVersion ::new ( 6 , 6 , 0 ) {
if kernel_version < KernelVersion ::new ( 6 , 6 , 0 ) {
eprintln! ( "skipping tcx_attach test on kernel {kernel_version:?}" ) ;
eprintln! ( "skipping tcx_attach test on kernel {kernel_version:?}" ) ;
@ -17,77 +22,113 @@ async fn tcx_attach() {
let _netns = NetNsGuard ::new ( ) ;
let _netns = NetNsGuard ::new ( ) ;
let mut program0 = EbpfLoader ::new ( )
// We need a dedicated `Ebpf` instance for each program that we load
. set_global ( "ORDER" , & 0 , true )
// since TCX does not allow the same program ID to be attached multiple
. load ( crate ::TCX )
// times to the same interface/direction.
. unwrap ( ) ;
let mut attached_programs : HashMap < & str , ( Ebpf , SchedClassifierLink ) > = HashMap ::new ( ) ;
let mut program1 = EbpfLoader ::new ( )
macro_rules! attach_program_with_linkorder {
. set_global ( "ORDER" , & 1 , true )
( $name :literal , $link_order :expr ) = > { {
. load ( crate ::TCX )
let mut loader = EbpfLoader ::new ( ) . load ( crate ::TCX ) . unwrap ( ) ;
. unwrap ( ) ;
let program : & mut SchedClassifier =
let mut program2 = EbpfLoader ::new ( )
loader . program_mut ( "tcx_next" ) . unwrap ( ) . try_into ( ) . unwrap ( ) ;
. set_global ( "ORDER" , & 2 , true )
program . load ( ) . unwrap ( ) ;
. load ( crate ::TCX )
let options = TcAttachOptions ::TcxOrder ( $link_order ) ;
. unwrap ( ) ;
let link_id = program
let mut program3 = EbpfLoader ::new ( )
. attach_with_options ( "lo" , TcAttachType ::Ingress , options )
. set_global ( "ORDER" , & 3 , true )
. load ( crate ::TCX )
. unwrap ( ) ;
. unwrap ( ) ;
let link = program . take_link ( link_id ) . unwrap ( ) ;
attached_programs . insert ( $name , ( loader , link ) ) ;
} } ;
}
let prog0 : & mut SchedClassifier = program0
// TODO: Assert in position 4 at the end of the test.
. program_mut ( "tcx_order" )
attach_program_with_linkorder ! ( "default" , LinkOrder ::default ( ) ) ;
// TODO: Assert in position 1 at the end of the test.
attach_program_with_linkorder ! ( "first" , LinkOrder ::first ( ) ) ;
// TODO: Assert in position 7 at the end of the test.
attach_program_with_linkorder ! ( "last" , LinkOrder ::last ( ) ) ;
// TODO: Assert in position 6 at the end of the test.
attach_program_with_linkorder ! (
"before_last" ,
LinkOrder ::before_link ( & attached_programs . get ( "last" ) . unwrap ( ) . 1 ) . unwrap ( )
) ;
// TODO: Assert in position 8 at the end of the test.
attach_program_with_linkorder ! (
"after_last" ,
LinkOrder ::after_link ( & attached_programs . get ( "last" ) . unwrap ( ) . 1 ) . unwrap ( )
) ;
// TODO: Assert in position 3 at the end of the test.
attach_program_with_linkorder ! (
"before_default" ,
LinkOrder ::before_program (
TryInto ::< & SchedClassifier > ::try_into (
attached_programs
. get ( "default" )
. unwrap ( )
. unwrap ( )
. try_into ( )
. 0
. unwrap ( ) ;
. program ( "tcx_next" )
prog0 . load ( ) . unwrap ( ) ;
. unwrap ( ) ,
)
let prog1 : & mut SchedClassifier = program1
. program_mut ( "tcx_order" )
. unwrap ( )
. unwrap ( )
. try_into ( )
)
. unwrap ( ) ;
prog1 . load ( ) . unwrap ( ) ;
let prog2 : & mut SchedClassifier = program2
. program_mut ( "tcx_order" )
. unwrap ( )
. unwrap ( )
. try_into ( )
) ;
. unwrap ( ) ;
// TODO: Assert in position 5 at the end of the test.
prog2 . load ( ) . unwrap ( ) ;
attach_program_with_linkorder ! (
"after_default" ,
let prog3 : & mut SchedClassifier = program3
LinkOrder ::after_program (
. program_mut ( "tcx_order" )
TryInto ::< & SchedClassifier > ::try_into (
attached_programs
. get ( "default" )
. unwrap ( )
. unwrap ( )
. try_into ( )
. 0
. unwrap ( ) ;
. program ( "tcx_next" )
prog3 . load ( ) . unwrap ( ) ;
. unwrap ( ) ,
)
// Test LinkOrder::last()
. unwrap ( )
let order : LinkOrder = LinkOrder ::last ( ) ;
)
let options = TcAttachOptions ::TcxOrder ( order ) ;
. unwrap ( )
prog0
) ;
. attach_with_options ( "lo" , TcAttachType ::Ingress , options )
// TODO: Assert in position 0 at the end of the test.
. unwrap ( ) ;
attach_program_with_linkorder ! (
"before_first" ,
// Test LinkOrder::after_program()
LinkOrder ::before_program_id ( unsafe {
let order = LinkOrder ::after_program ( prog0 ) . unwrap ( ) ;
ProgramId ::new (
let options = TcAttachOptions ::TcxOrder ( order ) ;
TryInto ::< & SchedClassifier > ::try_into (
let prog1_link_id = prog1
attached_programs
. attach_with_options ( "lo" , TcAttachType ::Ingress , options )
. get ( "first" )
. unwrap ( ) ;
. unwrap ( )
. 0
let prog1_link = prog1 . take_link ( prog1_link_id ) . unwrap ( ) ;
. program ( "tcx_next" )
. unwrap ( ) ,
// Test LinkOrder::after_link()
)
let order = LinkOrder ::after_link ( & prog1_link ) . unwrap ( ) ;
. unwrap ( )
let options = TcAttachOptions ::TcxOrder ( order ) ;
. info ( )
prog2
. unwrap ( )
. attach_with_options ( "lo" , TcAttachType ::Ingress , options )
. id ( ) ,
. unwrap ( ) ;
)
} )
// Test LinkOrder::last()
) ;
let options = TcAttachOptions ::TcxOrder ( LinkOrder ::last ( ) ) ;
// TODO: Assert in position 2 at the end of the test.
prog3
attach_program_with_linkorder ! (
. attach_with_options ( "lo" , TcAttachType ::Ingress , options )
"after_first" ,
. unwrap ( ) ;
LinkOrder ::after_program_id ( unsafe {
ProgramId ::new (
TryInto ::< & SchedClassifier > ::try_into (
attached_programs
. get ( "first" )
. unwrap ( )
. 0
. program ( "tcx_next" )
. unwrap ( ) ,
)
. unwrap ( )
. info ( )
. unwrap ( )
. id ( ) ,
)
} )
) ;
// TODO: Add code here to automatically verify the order after the API based
// on the BPF_PROG_QUERY syscall is implemented.
}
}