use crate::{BccError, BPF};
use bcc_sys::bccapi::bpf_prog_type_BPF_PROG_TYPE_XDP as BPF_PROG_TYPE_XDP;
#[allow(non_camel_case_types)]
#[repr(u32)]
pub enum Mode {
XDP_FLAGS_DRV_MODE = 1 << 2,
XDP_FLAGS_SKB_MODE = 1 << 1,
XDP_FLAGS_HW_MODE = 1 << 3,
}
#[allow(non_camel_case_types)]
const XDP_FLAGS_UPDATE_IF_NOEXIST: u32 = 1;
pub struct XDP {
handler: Option<String>,
device: Option<String>,
mode: Mode,
replace_existing_program: bool,
}
impl Default for XDP {
fn default() -> Self {
Self::new()
}
}
impl XDP {
pub fn new() -> Self {
Self {
device: None,
handler: None,
mode: Mode::XDP_FLAGS_DRV_MODE,
replace_existing_program: true,
}
}
pub fn handler<T: AsRef<str>>(mut self, name: T) -> Self {
self.handler = Some(name.as_ref().into());
self
}
pub fn device<T: AsRef<str>>(mut self, name: T) -> Self {
self.device = Some(name.as_ref().into());
self
}
pub fn mode(mut self, mode: Mode) -> Self {
self.mode = mode;
self
}
pub fn attach(self, bpf: &mut BPF) -> Result<(), BccError> {
let device = self.device.ok_or_else(|| BccError::InvalidXDP {
message: "device is required".into(),
})?;
let handler = self.handler.ok_or_else(|| BccError::InvalidXDP {
message: "handler is required".into(),
})?;
let flags = if self.replace_existing_program {
self.mode as u32
} else {
self.mode as u32 | XDP_FLAGS_UPDATE_IF_NOEXIST
};
let prog_fd = bpf.load(handler.as_str(), BPF_PROG_TYPE_XDP, 0, 0)?;
bpf.xdp
.insert(crate::core::XDP::new(handler, prog_fd, device, flags)?);
Ok(())
}
}