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! { /// Flags to configure the `XDP` operations pub struct XdpFlags: u32 { /// No flags. const NONE = 0; /// See [`libbpf_sys::XDP_FLAGS_UPDATE_IF_NOEXIST`]. const UPDATE_IF_NOEXIST = libbpf_sys::XDP_FLAGS_UPDATE_IF_NOEXIST as _; /// See [`libbpf_sys::XDP_FLAGS_SKB_MODE`]. const SKB_MODE = libbpf_sys::XDP_FLAGS_SKB_MODE as _; /// See [`libbpf_sys::XDP_FLAGS_DRV_MODE`]. const DRV_MODE = libbpf_sys::XDP_FLAGS_DRV_MODE as _; /// See [`libbpf_sys::XDP_FLAGS_HW_MODE`]. const HW_MODE = libbpf_sys::XDP_FLAGS_HW_MODE as _; /// See [`libbpf_sys::XDP_FLAGS_REPLACE`]. const REPLACE = libbpf_sys::XDP_FLAGS_REPLACE as _; /// See [`libbpf_sys::XDP_FLAGS_MODES`]. const MODES = libbpf_sys::XDP_FLAGS_MODES as _; /// See [`libbpf_sys::XDP_FLAGS_MASK`]. const MASK = libbpf_sys::XDP_FLAGS_MASK as _; } } /// Represents a XDP program. /// /// This struct exposes operations to attach, detach and query a XDP program #[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> { /// Create a new XDP instance with the given file descriptor of the /// `SEC("xdp")` [`Program`][crate::Program]. 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::() as libbpf_sys::size_t; xdp.query_opts.sz = size_of::() as libbpf_sys::size_t; xdp } /// Attach the XDP program to the given interface to start processing the /// packets /// /// # Notes /// Once a program is attached, it will outlive the userspace program. Make /// sure to detach the program if its not desired. 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) } /// Detach the XDP program from the interface 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) } /// Query to inspect the program pub fn query(&self, ifindex: i32, flags: XdpFlags) -> Result { 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) } /// Query to inspect the program identifier (prog_id) pub fn query_id(&self, ifindex: i32, flags: XdpFlags) -> Result { 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) } /// Replace an existing xdp program (identified by old_prog_fd) with this xdp program 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) } }