#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ExtendedBpfProgramFileDescriptor(RawFd);
impl Drop for ExtendedBpfProgramFileDescriptor
{
#[inline(always)]
fn drop(&mut self)
{
self.as_raw_fd().close()
}
}
impl AsRawFd for ExtendedBpfProgramFileDescriptor
{
#[inline(always)]
fn as_raw_fd(&self) -> RawFd
{
self.0
}
}
impl IntoRawFd for ExtendedBpfProgramFileDescriptor
{
#[inline(always)]
fn into_raw_fd(self) -> RawFd
{
self.as_raw_fd()
}
}
impl FromRawFd for ExtendedBpfProgramFileDescriptor
{
#[inline(always)]
unsafe fn from_raw_fd(fd: RawFd) -> Self
{
Self(fd)
}
}
impl FileDescriptor for ExtendedBpfProgramFileDescriptor
{
}
impl BpfFileDescriptor for ExtendedBpfProgramFileDescriptor
{
type Identifier = ExtendedBpfProgramIdentifier;
type Information = bpf_prog_info;
type Access = ();
const GetFileDescriptor: bpf_cmd = bpf_cmd::BPF_PROG_GET_FD_BY_ID;
const DefaultAccess: Self::Access = ();
#[inline(always)]
fn access_permissions_to_open_flags(_access: Self::Access) -> u32
{
0
}
}
impl UsedAsValueInArrayMapDescriptor for ExtendedBpfProgramFileDescriptor
{
#[inline(always)]
fn transmute_from_file_descriptor_copies(values: &[Self]) -> &[RawFd]
{
unsafe { transmute(values) }
}
}
impl ProvidesIdentifierWhenUsedAsValueInArrayMapDescriptor for ExtendedBpfProgramFileDescriptor
{
type Identifier = ExtendedBpfProgramIdentifier;
}
impl ExtendedBpfProgramFileDescriptor
{
pub fn test_run<C: Sized>(&self, context: &C, test_data: &[u8], expected_output_data_length: usize, repetitions: NonZeroU32) -> Result<TestRunResults<C>, Errno>
{
let mut attr = bpf_attr::default();
let mut context_out: C = unsafe_uninitialized();
let mut data_out = Vec::with_capacity(expected_output_data_length);
attr.test = BpfCommandProgramTestRun
{
prog_fd: self.as_raw_fd(),
retval: 0,
data_size_in: test_data.len() as u32,
data_size_out: data_out.capacity() as u32,
data_in: AlignedU64::from(test_data.as_ptr()),
data_out: AlignedU64::from(data_out.as_mut_ptr()),
repeat: repetitions,
duration: 0,
ctx_size_in: size_of::<C>() as u32,
ctx_size_out: size_of::<C>() as u32,
ctx_in: AlignedU64::from(context),
ctx_out: AlignedU64::from(&mut context_out),
};
let result = attr.syscall(bpf_cmd::BPF_PROG_TEST_RUN);
if likely!(result == 0)
{
let test = unsafe { attr.test };
let ctx_size_out = test.ctx_size_out;
debug_assert!(ctx_size_out <= size_of::<C>() as u32);
let data_size_out = test.data_size_out;
debug_assert!(data_size_out <= data_out.len() as u32);
unsafe { data_out.set_len(data_size_out as usize) };
data_out.shrink_to_fit();
Ok
(
TestRunResults
{
context: context_out,
data: data_out,
result_code: test.retval,
duration: test.duration,
}
)
}
else if likely!(result == -1)
{
Err(errno())
}
else
{
unreachable_code(format_args!("Unexpected result `{}` from bpf(BPF_PROG_TEST_RUN)", result))
}
}
}