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