1 use std::mem::size_of;
2 use std::os::unix::io::AsRawFd;
3 use std::os::unix::io::BorrowedFd;
4 
5 use bitflags::bitflags;
6 
7 use crate::util;
8 use crate::Result;
9 
10 bitflags! {
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)]
37 pub 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 
43 impl<'fd> Xdp<'fd> {
44     /// Create a new XDP instance with the given file descriptor of the
45     /// `SEC("xdp")` [`Program`][crate::Program].
new(fd: BorrowedFd<'fd>) -> Self46     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.
attach(&self, ifindex: i32, flags: XdpFlags) -> Result<()>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
detach(&self, ifindex: i32, flags: XdpFlags) -> Result<()>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
query(&self, ifindex: i32, flags: XdpFlags) -> Result<libbpf_sys::bpf_xdp_query_opts>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)
query_id(&self, ifindex: i32, flags: XdpFlags) -> Result<u32>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
replace(&self, ifindex: i32, old_prog_fd: BorrowedFd<'_>) -> Result<()>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 }
111