mod default_program;
mod program;
pub use default_program::default_program;
pub use program::{XdpAttachment, XdpFlags, XdpProgram};
#[derive(Debug, thiserror::Error)]
pub enum LoaderError {
#[error("XDP loader (aya): {0}")]
Aya(String),
#[error("vendored XDP program missing symbol `{0}`")]
SymbolMissing(&'static str),
#[error("vendored XDP program missing map `{0}`")]
MapMissing(&'static str),
#[error("with_default_program() conflicts with with_xsk_map()")]
ExclusiveBuilderOptions,
}
impl From<LoaderError> for crate::error::Error {
fn from(e: LoaderError) -> Self {
crate::error::Error::Loader(e.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
const REDIRECT_ALL_BYTECODE: &[u8] = include_bytes!("programs/redirect_all.bpf.o");
#[test]
fn vendored_bytecode_is_elf_bpf() {
assert_eq!(&REDIRECT_ALL_BYTECODE[0..4], b"\x7fELF");
assert_eq!(REDIRECT_ALL_BYTECODE[4], 2, "ELFCLASS64");
assert_eq!(REDIRECT_ALL_BYTECODE[5], 1, "ELFDATA2LSB");
assert_eq!(
u16::from_le_bytes([REDIRECT_ALL_BYTECODE[0x12], REDIRECT_ALL_BYTECODE[0x13]]),
247,
"EM_BPF"
);
}
#[test]
fn vendored_bytecode_has_expected_strings() {
let bytes = REDIRECT_ALL_BYTECODE;
let mut found_prog = false;
let mut found_map = false;
let prog_name = b"xdp_sock_prog\0";
let map_name = b"xsks_map\0";
for window in bytes.windows(prog_name.len()) {
if window == prog_name {
found_prog = true;
break;
}
}
for window in bytes.windows(map_name.len()) {
if window == map_name {
found_map = true;
break;
}
}
assert!(found_prog, "vendored .bpf.o missing `xdp_sock_prog` symbol");
assert!(found_map, "vendored .bpf.o missing `xsks_map` symbol");
}
#[test]
fn xdp_flags_round_trip_via_aya() {
let f = XdpFlags::DRV_MODE | XdpFlags::REPLACE;
let aya = f.to_aya();
assert!(aya.contains(aya::programs::XdpFlags::DRV_MODE));
assert!(aya.contains(aya::programs::XdpFlags::REPLACE));
}
}