| 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::<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 |
| } |
| |
| /// 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<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) |
| } |
| |
| /// Query to inspect the program identifier (prog_id) |
| 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) |
| } |
| |
| /// 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) |
| } |
| } |