use std::mem::size_of;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::BorrowedFd;
use bitflags::bitflags;
use crate::util;
use crate::Result;
bitflags! {
pub struct XdpFlags: u32 {
const NONE = 0;
const UPDATE_IF_NOEXIST = libbpf_sys::XDP_FLAGS_UPDATE_IF_NOEXIST as _;
const SKB_MODE = libbpf_sys::XDP_FLAGS_SKB_MODE as _;
const DRV_MODE = libbpf_sys::XDP_FLAGS_DRV_MODE as _;
const HW_MODE = libbpf_sys::XDP_FLAGS_HW_MODE as _;
const REPLACE = libbpf_sys::XDP_FLAGS_REPLACE as _;
const MODES = libbpf_sys::XDP_FLAGS_MODES as _;
const MASK = libbpf_sys::XDP_FLAGS_MASK as _;
}
}
#[derive(Debug)]
pub struct Xdp<'fd> {
fd: BorrowedFd<'fd>,
attach_opts: libbpf_sys::bpf_xdp_attach_opts,
query_opts: libbpf_sys::bpf_xdp_query_opts,
}
impl<'fd> Xdp<'fd> {
pub fn new(fd: BorrowedFd<'fd>) -> Self {
let mut xdp = Xdp {
fd,
attach_opts: libbpf_sys::bpf_xdp_attach_opts::default(),
query_opts: libbpf_sys::bpf_xdp_query_opts::default(),
};
xdp.attach_opts.sz = size_of::<libbpf_sys::bpf_xdp_attach_opts>() as libbpf_sys::size_t;
xdp.query_opts.sz = size_of::<libbpf_sys::bpf_xdp_query_opts>() as libbpf_sys::size_t;
xdp
}
pub fn attach(&self, ifindex: i32, flags: XdpFlags) -> Result<()> {
let ret = unsafe {
libbpf_sys::bpf_xdp_attach(
ifindex,
self.fd.as_raw_fd(),
flags.bits(),
&self.attach_opts,
)
};
util::parse_ret(ret)
}
pub fn detach(&self, ifindex: i32, flags: XdpFlags) -> Result<()> {
let ret = unsafe { libbpf_sys::bpf_xdp_detach(ifindex, flags.bits(), &self.attach_opts) };
util::parse_ret(ret)
}
pub fn query(&self, ifindex: i32, flags: XdpFlags) -> Result<libbpf_sys::bpf_xdp_query_opts> {
let mut opts = self.query_opts;
let err = unsafe { libbpf_sys::bpf_xdp_query(ifindex, flags.bits() as i32, &mut opts) };
util::parse_ret(err).map(|()| opts)
}
pub fn query_id(&self, ifindex: i32, flags: XdpFlags) -> Result<u32> {
let mut prog_id = 0;
let err =
unsafe { libbpf_sys::bpf_xdp_query_id(ifindex, flags.bits() as i32, &mut prog_id) };
util::parse_ret(err).map(|()| prog_id)
}
pub fn replace(&self, ifindex: i32, old_prog_fd: BorrowedFd<'_>) -> Result<()> {
let mut opts = self.attach_opts;
opts.old_prog_fd = old_prog_fd.as_raw_fd();
let ret = unsafe {
libbpf_sys::bpf_xdp_attach(
ifindex,
self.fd.as_raw_fd(),
XdpFlags::REPLACE.bits(),
&opts,
)
};
util::parse_ret(ret)
}
}