use std::os::fd::RawFd;
use aya::{
Ebpf,
maps::XskMap,
programs::{Xdp, XdpFlags},
};
use aya::programs::xdp::XdpLinkId;
static XDP_PROG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/dns_xdp.o"));
#[derive(Clone, Copy, Debug)]
pub enum XdpMode { Drv, Skb }
pub struct XdpHandle {
bpf: Ebpf,
link_id: Option<XdpLinkId>,
pub mode: XdpMode,
}
impl Drop for XdpHandle {
fn drop(&mut self) {
if let Some(id) = self.link_id.take() {
if let Some(prog) = self.bpf.program_mut("dns_xdp") {
if let Ok(xdp) = <&mut Xdp>::try_from(prog) {
let _ = xdp.detach(id);
}
}
}
}
}
impl XdpHandle {
pub fn load(iface: &str) -> Result<Self, String> {
let words = XDP_PROG.len().div_ceil(8);
let mut storage: Vec<u64> = vec![0u64; words];
unsafe {
std::ptr::copy_nonoverlapping(
XDP_PROG.as_ptr(),
storage.as_mut_ptr() as *mut u8,
XDP_PROG.len(),
);
}
let aligned = unsafe {
std::slice::from_raw_parts(storage.as_ptr() as *const u8, XDP_PROG.len())
};
let mut bpf = Ebpf::load(aligned)
.map_err(|e| format!("BPF ELF load failed: {e}"))?;
let program: &mut Xdp = bpf
.program_mut("dns_xdp")
.ok_or_else(|| "dns_xdp program section not found in ELF".to_string())?
.try_into()
.map_err(|e| format!("program type mismatch: {e}"))?;
program.load()
.map_err(|e| format!("XDP prog load failed: {e}"))?;
let (link_id, mode) = program
.attach(iface, XdpFlags::DRV_MODE)
.map(|id| (id, XdpMode::Drv))
.or_else(|_| program.attach(iface, XdpFlags::SKB_MODE).map(|id| (id, XdpMode::Skb)))
.map_err(|e| format!("XDP attach to {iface} failed: {e}"))?;
tracing::info!(iface = %iface, link_id = ?link_id, mode = ?mode, "XDP program attached");
Ok(XdpHandle { bpf, link_id: Some(link_id), mode })
}
pub fn register_socket(&mut self, queue_id: u32, sock_fd: RawFd) -> Result<(), String> {
let map = self.bpf
.map_mut("XSKS")
.ok_or_else(|| "XSKS map not found in BPF object".to_string())?;
let mut xsk_map = XskMap::try_from(map)
.map_err(|e| format!("XSKS is not an XskMap: {e}"))?;
xsk_map
.set(queue_id, sock_fd, 0)
.map_err(|e| format!("XskMap::set q={queue_id} fd={sock_fd}: {e}"))
}
}