libbpf_rs/
xdp.rs

1use std::mem::size_of;
2use std::os::unix::io::AsRawFd;
3use std::os::unix::io::BorrowedFd;
4
5use bitflags::bitflags;
6
7use crate::util;
8use crate::Result;
9
10bitflags! {
11    /// Flags to configure the `XDP` operations
12    pub struct XdpFlags: u32 {
13        /// No flags.
14        const NONE              = 0;
15        /// See [`libbpf_sys::XDP_FLAGS_UPDATE_IF_NOEXIST`].
16        const UPDATE_IF_NOEXIST = libbpf_sys::XDP_FLAGS_UPDATE_IF_NOEXIST as _;
17        /// See [`libbpf_sys::XDP_FLAGS_SKB_MODE`].
18        const SKB_MODE          = libbpf_sys::XDP_FLAGS_SKB_MODE as _;
19        /// See [`libbpf_sys::XDP_FLAGS_DRV_MODE`].
20        const DRV_MODE          = libbpf_sys::XDP_FLAGS_DRV_MODE as _;
21        /// See [`libbpf_sys::XDP_FLAGS_HW_MODE`].
22        const HW_MODE           = libbpf_sys::XDP_FLAGS_HW_MODE as _;
23        /// See [`libbpf_sys::XDP_FLAGS_REPLACE`].
24        const REPLACE           = libbpf_sys::XDP_FLAGS_REPLACE as _;
25        /// See [`libbpf_sys::XDP_FLAGS_MODES`].
26        const MODES             = libbpf_sys::XDP_FLAGS_MODES as _;
27        /// See [`libbpf_sys::XDP_FLAGS_MASK`].
28        const MASK              = libbpf_sys::XDP_FLAGS_MASK as _;
29    }
30
31}
32
33/// Represents a XDP program.
34///
35/// This struct exposes operations to attach, detach and query a XDP program
36#[derive(Debug)]
37pub struct Xdp<'fd> {
38    fd: BorrowedFd<'fd>,
39    attach_opts: libbpf_sys::bpf_xdp_attach_opts,
40    query_opts: libbpf_sys::bpf_xdp_query_opts,
41}
42
43impl<'fd> Xdp<'fd> {
44    /// Create a new XDP instance with the given file descriptor of the
45    /// `SEC("xdp")` [`Program`][crate::Program].
46    pub fn new(fd: BorrowedFd<'fd>) -> Self {
47        let mut xdp = Xdp {
48            fd,
49            attach_opts: libbpf_sys::bpf_xdp_attach_opts::default(),
50            query_opts: libbpf_sys::bpf_xdp_query_opts::default(),
51        };
52        xdp.attach_opts.sz = size_of::<libbpf_sys::bpf_xdp_attach_opts>() as libbpf_sys::size_t;
53        xdp.query_opts.sz = size_of::<libbpf_sys::bpf_xdp_query_opts>() as libbpf_sys::size_t;
54        xdp
55    }
56
57    /// Attach the XDP program to the given interface to start processing the
58    /// packets
59    ///
60    /// # Notes
61    /// Once a program is attached, it will outlive the userspace program. Make
62    /// sure to detach the program if its not desired.
63    pub fn attach(&self, ifindex: i32, flags: XdpFlags) -> Result<()> {
64        let ret = unsafe {
65            libbpf_sys::bpf_xdp_attach(
66                ifindex,
67                self.fd.as_raw_fd(),
68                flags.bits(),
69                &self.attach_opts,
70            )
71        };
72        util::parse_ret(ret)
73    }
74
75    /// Detach the XDP program from the interface
76    pub fn detach(&self, ifindex: i32, flags: XdpFlags) -> Result<()> {
77        let ret = unsafe { libbpf_sys::bpf_xdp_detach(ifindex, flags.bits(), &self.attach_opts) };
78        util::parse_ret(ret)
79    }
80
81    /// Query to inspect the program
82    pub fn query(&self, ifindex: i32, flags: XdpFlags) -> Result<libbpf_sys::bpf_xdp_query_opts> {
83        let mut opts = self.query_opts;
84        let err = unsafe { libbpf_sys::bpf_xdp_query(ifindex, flags.bits() as i32, &mut opts) };
85        util::parse_ret(err).map(|()| opts)
86    }
87
88    /// Query to inspect the program identifier (prog_id)
89    pub fn query_id(&self, ifindex: i32, flags: XdpFlags) -> Result<u32> {
90        let mut prog_id = 0;
91        let err =
92            unsafe { libbpf_sys::bpf_xdp_query_id(ifindex, flags.bits() as i32, &mut prog_id) };
93        util::parse_ret(err).map(|()| prog_id)
94    }
95
96    /// Replace an existing xdp program (identified by old_prog_fd) with this xdp program
97    pub fn replace(&self, ifindex: i32, old_prog_fd: BorrowedFd<'_>) -> Result<()> {
98        let mut opts = self.attach_opts;
99        opts.old_prog_fd = old_prog_fd.as_raw_fd();
100        let ret = unsafe {
101            libbpf_sys::bpf_xdp_attach(
102                ifindex,
103                self.fd.as_raw_fd(),
104                XdpFlags::REPLACE.bits(),
105                &opts,
106            )
107        };
108        util::parse_ret(ret)
109    }
110}