use aya::Ebpf;
use aya::maps::xdp::XskMap;
use aya::programs::{Xdp, XdpFlags as AyaXdpFlags, links::FdLink};
use crate::afxdp::XdpSocket;
use crate::error::Error;
use super::LoaderError;
bitflags::bitflags! {
#[derive(Debug, Clone, Copy)]
pub struct XdpFlags: u32 {
const SKB_MODE = 1 << 1;
const DRV_MODE = 1 << 2;
const HW_MODE = 1 << 3;
const REPLACE = 1 << 4;
}
}
impl XdpFlags {
pub(crate) fn to_aya(self) -> AyaXdpFlags {
let mut out = AyaXdpFlags::default();
if self.contains(XdpFlags::SKB_MODE) {
out |= AyaXdpFlags::SKB_MODE;
}
if self.contains(XdpFlags::DRV_MODE) {
out |= AyaXdpFlags::DRV_MODE;
}
if self.contains(XdpFlags::HW_MODE) {
out |= AyaXdpFlags::HW_MODE;
}
if self.contains(XdpFlags::REPLACE) {
out |= AyaXdpFlags::REPLACE;
}
out
}
}
pub struct XdpProgram {
bpf: Ebpf,
program_name: String,
map_name: String,
}
impl XdpProgram {
pub(crate) fn new(bpf: Ebpf, program_name: &str, map_name: &str) -> Self {
Self {
bpf,
program_name: program_name.to_string(),
map_name: map_name.to_string(),
}
}
pub fn from_aya(bpf: Ebpf, program_name: &str, map_name: &str) -> Self {
Self::new(bpf, program_name, map_name)
}
pub fn xsk_map(&mut self) -> Result<XskMap<&mut aya::maps::MapData>, Error> {
let map = self
.bpf
.map_mut(&self.map_name)
.ok_or(LoaderError::MapMissing("xsks_map"))?;
XskMap::try_from(map).map_err(|e| LoaderError::Aya(e.to_string()).into())
}
pub fn register(&mut self, queue_id: u32, xsk: &XdpSocket) -> Result<(), Error> {
use std::os::fd::AsRawFd;
let mut map = self.xsk_map()?;
let fd: i32 = xsk.as_raw_fd();
map.set(queue_id, fd, 0)
.map_err(|e| LoaderError::Aya(e.to_string()).into())
}
pub fn attach(mut self, iface: &str, flags: XdpFlags) -> Result<XdpAttachment, Error> {
let prog: &mut Xdp = self
.bpf
.program_mut(&self.program_name)
.ok_or(LoaderError::SymbolMissing("xdp_sock_prog"))?
.try_into()
.map_err(|e: aya::programs::ProgramError| LoaderError::Aya(e.to_string()))?;
prog.load().map_err(|e| LoaderError::Aya(e.to_string()))?;
let link_id = prog
.attach(iface, flags.to_aya())
.map_err(|e| LoaderError::Aya(e.to_string()))?;
let xdp_link = prog
.take_link(link_id)
.map_err(|e| LoaderError::Aya(e.to_string()))?;
let owned: FdLink = xdp_link
.try_into()
.map_err(|e: aya::programs::links::LinkError| LoaderError::Aya(e.to_string()))?;
Ok(XdpAttachment {
_link: owned,
_program: self,
})
}
}
impl std::fmt::Debug for XdpProgram {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("XdpProgram")
.field("program_name", &self.program_name)
.field("map_name", &self.map_name)
.finish()
}
}
pub struct XdpAttachment {
_link: FdLink,
_program: XdpProgram,
}
impl XdpAttachment {
pub fn xsk_map(&mut self) -> Result<XskMap<&mut aya::maps::MapData>, Error> {
self._program.xsk_map()
}
}
impl std::fmt::Debug for XdpAttachment {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("XdpAttachment")
.field("program", &self._program)
.finish()
}
}