@ -1,12 +1,7 @@
 
		
	
		
			
				use   std ::collections ::HashMap ;  
		
	
		
			
				
 
		
	
		
			
				use   aya ::{  
		
	
		
			
				     programs ::{  
		
	
		
			
				         tc ::{ SchedClassifierLink ,   TcAttachOptions } ,  
		
	
		
			
				         LinkOrder ,   ProgramId ,   SchedClassifier ,   TcAttachType ,  
		
	
		
			
				     } ,  
		
	
		
			
				     programs ::{ tc ::TcAttachOptions ,   LinkOrder ,   ProgramId ,   SchedClassifier ,   TcAttachType } ,  
		
	
		
			
				     util ::KernelVersion ,  
		
	
		
			
				     Ebpf ,   EbpfLoader ,  
		
	
		
			
				     Ebpf ,  
		
	
		
			
				} ;  
		
	
		
			
				use   test_log ::test ;  
		
	
		
			
				
 
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
			
			@ -25,110 +20,97 @@ async fn tcx() {
 
		
	
		
			
				     // We need a dedicated `Ebpf` instance for each program that we load
  
		
	
		
			
				     // since TCX does not allow the same program ID to be attached multiple
  
		
	
		
			
				     // times to the same interface/direction.
  
		
	
		
			
				     let   mut   attached_programs : HashMap < & str ,   ( Ebpf ,   SchedClassifierLink ) >   =   HashMap ::new ( ) ;  
		
	
		
			
				     //
  
		
	
		
			
				     // Variables declared within this macro are within a closure scope to avoid
  
		
	
		
			
				     // variable name conflicts.
  
		
	
		
			
				     //
  
		
	
		
			
				     // Yields a tuple of the `Ebpf` which must remain in scope for the duration
  
		
	
		
			
				     // of the test, and the link ID of the attached program.
  
		
	
		
			
				     macro_rules!   attach_program_with_linkorder   {  
		
	
		
			
				         ( $name :literal , $link_order :expr )   = >   { {  
		
	
		
			
				             let   mut   loader   =   EbpfLoader ::new ( ) . load ( crate ::TCX ) . unwrap ( ) ;  
		
	
		
			
				         ( $ link_order:expr )   = >   { {  
		
	
		
			
				             let   mut   ebpf  =   Ebpf :: load ( crate ::TCX ) . unwrap ( ) ;  
		
	
		
			
				             let   program : & mut   SchedClassifier   =  
		
	
		
			
				                 loader . program_mut ( "tcx_next" ) . unwrap ( ) . try_into ( ) . unwrap ( ) ;  
		
	
		
			
				                 ebpf . program_mut ( "tcx_next" ) . unwrap ( ) . try_into ( ) . unwrap ( ) ;  
		
	
		
			
				             program . load ( ) . unwrap ( ) ;  
		
	
		
			
				             let   options   =   TcAttachOptions ::TcxOrder ( $link_order ) ;  
		
	
		
			
				             let   link_id   =   program  
		
	
		
			
				                 . attach_with_options ( "lo" ,   TcAttachType ::Ingress ,   options )  
		
	
		
			
				                 . attach_with_options (  
		
	
		
			
				                     "lo" ,  
		
	
		
			
				                     TcAttachType ::Ingress ,  
		
	
		
			
				                     TcAttachOptions ::TcxOrder ( $link_order ) ,  
		
	
		
			
				                 )  
		
	
		
			
				                 . unwrap ( ) ;  
		
	
		
			
				             let   link   =   program . take_link ( link_id ) . unwrap ( ) ;  
		
	
		
			
				             attached_programs . insert ( $name ,   ( loader ,   link ) ) ;  
		
	
		
			
				             ( ebpf ,   link_id )  
		
	
		
			
				         } } ;  
		
	
		
			
				     }  
		
	
		
			
				
 
		
	
		
			
				     // TODO: Assert in position 4 at the end of the test.
  
		
	
		
			
				     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 ( )  
		
	
		
			
				                     . 0  
		
	
		
			
				                     . program ( "tcx_next" )  
		
	
		
			
				                     . unwrap ( ) ,  
		
	
		
			
				             )  
		
	
		
			
				     let   ( default ,   _ )   =   attach_program_with_linkorder ! ( LinkOrder ::default ( ) ) ;  
		
	
		
			
				     let   ( first ,   _ )   =   attach_program_with_linkorder ! ( LinkOrder ::first ( ) ) ;  
		
	
		
			
				     let   ( mut   last ,   last_link_id )   =   attach_program_with_linkorder ! ( LinkOrder ::last ( ) ) ;  
		
	
		
			
				
 
		
	
		
			
				     let   default_prog : & SchedClassifier   =   default . program ( "tcx_next" ) . unwrap ( ) . try_into ( ) . unwrap ( ) ;  
		
	
		
			
				     let   first_prog : & SchedClassifier   =   first . program ( "tcx_next" ) . unwrap ( ) . try_into ( ) . unwrap ( ) ;  
		
	
		
			
				     let   last_prog : & mut   SchedClassifier   =   last . program_mut ( "tcx_next" ) . unwrap ( ) . try_into ( ) . unwrap ( ) ;  
		
	
		
			
				
 
		
	
		
			
				     let   last_link   =   last_prog . take_link ( last_link_id ) . unwrap ( ) ;  
		
	
		
			
				
 
		
	
		
			
				     let   ( before_last ,   _ )   =  
		
	
		
			
				         attach_program_with_linkorder ! ( LinkOrder ::before_link ( & last_link ) . unwrap ( ) ) ;  
		
	
		
			
				     let   ( after_last ,   _ )   =  
		
	
		
			
				         attach_program_with_linkorder ! ( LinkOrder ::after_link ( & last_link ) . unwrap ( ) ) ;  
		
	
		
			
				
 
		
	
		
			
				     let   ( before_default ,   _ )   =  
		
	
		
			
				         attach_program_with_linkorder ! ( LinkOrder ::before_program ( default_prog ) . unwrap ( ) ) ;  
		
	
		
			
				     let   ( after_default ,   _ )   =  
		
	
		
			
				         attach_program_with_linkorder ! ( LinkOrder ::after_program ( default_prog ) . unwrap ( ) ) ;  
		
	
		
			
				
 
		
	
		
			
				     let   ( before_first ,   _ )   =   attach_program_with_linkorder ! ( LinkOrder ::before_program_id ( unsafe   {  
		
	
		
			
				         ProgramId ::new ( first_prog . info ( ) . unwrap ( ) . id ( ) )  
		
	
		
			
				     } ) ) ;  
		
	
		
			
				     let   ( after_first ,   _ )   =   attach_program_with_linkorder ! ( LinkOrder ::after_program_id ( unsafe   {  
		
	
		
			
				         ProgramId ::new ( first_prog . info ( ) . unwrap ( ) . id ( ) )  
		
	
		
			
				     } ) ) ;  
		
	
		
			
				
 
		
	
		
			
				     let   expected_order   =   [  
		
	
		
			
				         before_first  
		
	
		
			
				             . program ( "tcx_next" )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				         )  
		
	
		
			
				         . unwrap ( )  
		
	
		
			
				     ) ;  
		
	
		
			
				     // TODO: Assert in position 5 at the end of the test.
  
		
	
		
			
				     attach_program_with_linkorder ! (  
		
	
		
			
				         "after_default" ,  
		
	
		
			
				         LinkOrder ::after_program (  
		
	
		
			
				             TryInto ::< & SchedClassifier > ::try_into (  
		
	
		
			
				                 attached_programs  
		
	
		
			
				                     . get ( "default" )  
		
	
		
			
				                     . unwrap ( )  
		
	
		
			
				                     . 0  
		
	
		
			
				                     . program ( "tcx_next" )  
		
	
		
			
				                     . unwrap ( ) ,  
		
	
		
			
				             )  
		
	
		
			
				             . info ( )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				         )  
		
	
		
			
				         . unwrap ( )  
		
	
		
			
				     ) ;  
		
	
		
			
				     // TODO: Assert in position 0 at the end of the test.
  
		
	
		
			
				     attach_program_with_linkorder ! (  
		
	
		
			
				         "before_first" ,  
		
	
		
			
				         LinkOrder ::before_program_id ( unsafe   {  
		
	
		
			
				             ProgramId ::new (  
		
	
		
			
				                 TryInto ::< & SchedClassifier > ::try_into (  
		
	
		
			
				                     attached_programs  
		
	
		
			
				                         . get ( "first" )  
		
	
		
			
				                         . unwrap ( )  
		
	
		
			
				                         . 0  
		
	
		
			
				                         . program ( "tcx_next" )  
		
	
		
			
				                         . unwrap ( ) ,  
		
	
		
			
				                 )  
		
	
		
			
				                 . unwrap ( )  
		
	
		
			
				                 . info ( )  
		
	
		
			
				                 . unwrap ( )  
		
	
		
			
				                 . id ( ) ,  
		
	
		
			
				             )  
		
	
		
			
				         } )  
		
	
		
			
				     ) ;  
		
	
		
			
				     // TODO: Assert in position 2 at the end of the test.
  
		
	
		
			
				     attach_program_with_linkorder ! (  
		
	
		
			
				         "after_first" ,  
		
	
		
			
				         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 ( ) ,  
		
	
		
			
				             )  
		
	
		
			
				         } )  
		
	
		
			
				             . id ( ) ,  
		
	
		
			
				         first_prog . info ( ) . unwrap ( ) . id ( ) ,  
		
	
		
			
				         after_first  
		
	
		
			
				             . program ( "tcx_next" )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				             . info ( )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				             . id ( ) ,  
		
	
		
			
				         before_default  
		
	
		
			
				             . program ( "tcx_next" )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				             . info ( )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				             . id ( ) ,  
		
	
		
			
				         default_prog . info ( ) . unwrap ( ) . id ( ) ,  
		
	
		
			
				         after_default  
		
	
		
			
				             . program ( "tcx_next" )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				             . info ( )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				             . id ( ) ,  
		
	
		
			
				         before_last  
		
	
		
			
				             . program ( "tcx_next" )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				             . info ( )  
		
	
		
			
				             . unwrap ( )  
		
	
		
			
				             . id ( ) ,  
		
	
		
			
				         last_prog . info ( ) . unwrap ( ) . id ( ) ,  
		
	
		
			
				         after_last . program ( "tcx_next" ) . unwrap ( ) . info ( ) . unwrap ( ) . id ( ) ,  
		
	
		
			
				     ] ;  
		
	
		
			
				
 
		
	
		
			
				     let   ( revision ,   got_order )   =   SchedClassifier ::query_tcx ( "lo" ,   TcAttachType ::Ingress ) . unwrap ( ) ;  
		
	
		
			
				     assert_eq! ( revision ,   ( expected_order . len ( )   +   1 )   as   u64 ) ;  
		
	
		
			
				     assert_eq! (  
		
	
		
			
				         got_order . iter ( ) . map ( | p |   p . id ( ) ) . collect ::< Vec < _ > > ( ) ,  
		
	
		
			
				         expected_order  
		
	
		
			
				     ) ;  
		
	
		
			
				     // TODO: Add code here to automatically verify the order after the API based
  
		
	
		
			
				     // on the BPF_PROG_QUERY syscall is implemented.
  
		
	
		
			
				}