|  |  | @ -1,4 +1,4 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | use std::{ffi::CStr, mem::MaybeUninit, net::UdpSocket, num::NonZeroU32, time::Duration}; |  |  |  | use std::{mem::MaybeUninit, net::UdpSocket, num::NonZeroU32, time::Duration}; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | use aya::{ |  |  |  | use aya::{ | 
			
		
	
		
		
			
				
					
					|  |  |  |     maps::{Array, CpuMap, XskMap}, |  |  |  |     maps::{Array, CpuMap, XskMap}, | 
			
		
	
	
		
		
			
				
					|  |  | @ -9,11 +9,11 @@ use object::{Object, ObjectSection, ObjectSymbol, SymbolSection}; | 
			
		
	
		
		
			
				
					
					|  |  |  | use test_log::test; |  |  |  | use test_log::test; | 
			
		
	
		
		
			
				
					
					|  |  |  | use xdpilone::{BufIdx, IfInfo, Socket, SocketConfig, Umem, UmemConfig}; |  |  |  | use xdpilone::{BufIdx, IfInfo, Socket, SocketConfig, Umem, UmemConfig}; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::utils::NetNsGuard; |  |  |  | use crate::utils::{NetNsGuard, IP_ADDR_1, IP_ADDR_2}; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #[test] |  |  |  | #[test] | 
			
		
	
		
		
			
				
					
					|  |  |  | fn af_xdp() { |  |  |  | fn af_xdp() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     let _netns = NetNsGuard::new(); |  |  |  |     let netns = NetNsGuard::new(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let mut bpf = Ebpf::load(crate::REDIRECT).unwrap(); |  |  |  |     let mut bpf = Ebpf::load(crate::REDIRECT).unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     let mut socks: XskMap<_> = bpf.take_map("SOCKS").unwrap().try_into().unwrap(); |  |  |  |     let mut socks: XskMap<_> = bpf.take_map("SOCKS").unwrap().try_into().unwrap(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -24,7 +24,8 @@ fn af_xdp() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         .try_into() |  |  |  |         .try_into() | 
			
		
	
		
		
			
				
					
					|  |  |  |         .unwrap(); |  |  |  |         .unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     xdp.load().unwrap(); |  |  |  |     xdp.load().unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     xdp.attach("lo", XdpFlags::default()).unwrap(); |  |  |  |     xdp.attach_to_if_index(netns.if_idx2, XdpFlags::default()) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         .unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // So this needs to be page aligned. Pages are 4k on all mainstream architectures except for
 |  |  |  |     // So this needs to be page aligned. Pages are 4k on all mainstream architectures except for
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Apple Silicon which uses 16k pages. So let's align on that for tests to run natively there.
 |  |  |  |     // Apple Silicon which uses 16k pages. So let's align on that for tests to run natively there.
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -41,9 +42,7 @@ fn af_xdp() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     }; |  |  |  |     }; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let mut iface = IfInfo::invalid(); |  |  |  |     let mut iface = IfInfo::invalid(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     iface |  |  |  |     iface.from_ifindex(netns.if_idx1).unwrap(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         .from_name(CStr::from_bytes_with_nul(b"lo\0").unwrap()) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .unwrap(); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     let sock = Socket::with_shared(&iface, &umem).unwrap(); |  |  |  |     let sock = Socket::with_shared(&iface, &umem).unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let mut fq_cq = umem.fq_cq(&sock).unwrap(); // Fill Queue / Completion Queue
 |  |  |  |     let mut fq_cq = umem.fq_cq(&sock).unwrap(); // Fill Queue / Completion Queue
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -66,9 +65,12 @@ fn af_xdp() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     writer.insert_once(frame.offset); |  |  |  |     writer.insert_once(frame.offset); | 
			
		
	
		
		
			
				
					
					|  |  |  |     writer.commit(); |  |  |  |     writer.commit(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let sock = UdpSocket::bind("127.0.0.1:0").unwrap(); |  |  |  |     let sock = UdpSocket::bind((IP_ADDR_1, 0)).unwrap(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     let port = sock.local_addr().unwrap().port(); |  |  |  |     let src_port = sock.local_addr().unwrap().port(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     sock.send_to(b"hello AF_XDP", "127.0.0.1:1777").unwrap(); |  |  |  | 
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     const DST_PORT: u16 = 1777; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     sock.send_to(b"hello AF_XDP", (IP_ADDR_2, DST_PORT)) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         .unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     assert_eq!(rx.available(), 1); |  |  |  |     assert_eq!(rx.available(), 1); | 
			
		
	
		
		
			
				
					
					|  |  |  |     let desc = rx.receive(1).read().unwrap(); |  |  |  |     let desc = rx.receive(1).read().unwrap(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -81,8 +83,8 @@ fn af_xdp() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     let (ip, buf) = buf.split_at(20); |  |  |  |     let (ip, buf) = buf.split_at(20); | 
			
		
	
		
		
			
				
					
					|  |  |  |     assert_eq!(ip[9], 17); // UDP
 |  |  |  |     assert_eq!(ip[9], 17); // UDP
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let (udp, payload) = buf.split_at(8); |  |  |  |     let (udp, payload) = buf.split_at(8); | 
			
		
	
		
		
			
				
					
					|  |  |  |     assert_eq!(&udp[0..2], port.to_be_bytes().as_slice()); // Source
 |  |  |  |     assert_eq!(&udp[0..2], src_port.to_be_bytes().as_slice()); // Source
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     assert_eq!(&udp[2..4], 1777u16.to_be_bytes().as_slice()); // Dest
 |  |  |  |     assert_eq!(&udp[2..4], DST_PORT.to_be_bytes().as_slice()); // Dest
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     assert_eq!(payload, b"hello AF_XDP"); |  |  |  |     assert_eq!(payload, b"hello AF_XDP"); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -134,7 +136,7 @@ fn map_load() { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #[test] |  |  |  | #[test] | 
			
		
	
		
		
			
				
					
					|  |  |  | fn cpumap_chain() { |  |  |  | fn cpumap_chain() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     let _netns = NetNsGuard::new(); |  |  |  |     let netns = NetNsGuard::new(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let mut bpf = Ebpf::load(crate::REDIRECT).unwrap(); |  |  |  |     let mut bpf = Ebpf::load(crate::REDIRECT).unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -157,20 +159,24 @@ fn cpumap_chain() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Load the main program
 |  |  |  |     // Load the main program
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let xdp: &mut Xdp = bpf.program_mut("redirect_cpu").unwrap().try_into().unwrap(); |  |  |  |     let xdp: &mut Xdp = bpf.program_mut("redirect_cpu").unwrap().try_into().unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     xdp.load().unwrap(); |  |  |  |     xdp.load().unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     xdp.attach("lo", XdpFlags::default()).unwrap(); |  |  |  |     xdp.attach_to_if_index(netns.if_idx2, XdpFlags::default()) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         .unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     const PAYLOAD: &str = "hello cpumap"; |  |  |  |     const PAYLOAD: &str = "hello cpumap"; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let sock = UdpSocket::bind("127.0.0.1:0").unwrap(); |  |  |  |     let sock1 = UdpSocket::bind((IP_ADDR_1, 0)).unwrap(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     let addr = sock.local_addr().unwrap(); |  |  |  |     let sock2 = UdpSocket::bind((IP_ADDR_2, 0)).unwrap(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     sock.set_read_timeout(Some(Duration::from_secs(60))) |  |  |  |     sock2 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         .set_read_timeout(Some(Duration::from_secs(60))) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         .unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     sock1 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         .send_to(PAYLOAD.as_bytes(), sock2.local_addr().unwrap()) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .unwrap(); |  |  |  |         .unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     sock.send_to(PAYLOAD.as_bytes(), addr).unwrap(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Read back the packet to ensure it went through the entire network stack, including our two
 |  |  |  |     // Read back the packet to ensure it went through the entire network stack, including our two
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // probes.
 |  |  |  |     // probes.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let mut buf = [0u8; PAYLOAD.len() + 1]; |  |  |  |     let mut buf = [0u8; PAYLOAD.len() + 1]; | 
			
		
	
		
		
			
				
					
					|  |  |  |     let n = sock.recv(&mut buf).unwrap(); |  |  |  |     let n = sock2.recv(&mut buf).unwrap(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     assert_eq!(&buf[..n], PAYLOAD.as_bytes()); |  |  |  |     assert_eq!(&buf[..n], PAYLOAD.as_bytes()); | 
			
		
	
		
		
			
				
					
					|  |  |  |     assert_eq!(hits.get(&0, 0).unwrap(), 1); |  |  |  |     assert_eq!(hits.get(&0, 0).unwrap(), 1); | 
			
		
	
	
		
		
			
				
					|  |  | 
 |