Jelajahi Sumber

Merge pull request #346 from vadorovsky/skb-load-bytes

bpf: Add `load_bytes` method to SKB context
Michal Rostecki 2 tahun lalu
induk
melakukan
480f6180f5
1 mengubah file dengan 76 tambahan dan 0 penghapusan
  1. 76 0
      bpf/aya-bpf/src/programs/sk_buff.rs

+ 76 - 0
bpf/aya-bpf/src/programs/sk_buff.rs

@@ -1,4 +1,5 @@
 use core::{
+    cmp,
     ffi::c_void,
     mem::{self, MaybeUninit},
 };
@@ -65,6 +66,81 @@ impl SkBuffContext {
         }
     }
 
+    /// Reads some bytes from the packet into the specified buffer, returning
+    /// how many bytes were read.
+    ///
+    /// Starts reading at `offset` and reads at most `dst.len()` or
+    /// `self.len() - offset` bytes, depending on which one is smaller.
+    ///
+    /// # Examples
+    ///
+    /// Read into a `PerCpuArray`.
+    ///
+    /// ```no_run
+    /// use core::mem;
+    ///
+    /// use aya_bpf::{bindings::TC_ACT_PIPE, macros::map, maps::PerCpuArray, programs::SkBuffContext};
+    /// # #[allow(non_camel_case_types)]
+    /// # struct ethhdr {};
+    /// # #[allow(non_camel_case_types)]
+    /// # struct iphdr {};
+    /// # #[allow(non_camel_case_types)]
+    /// # struct tcphdr {};
+    ///
+    /// const ETH_HDR_LEN: usize = mem::size_of::<ethhdr>();
+    /// const IP_HDR_LEN: usize = mem::size_of::<iphdr>();
+    /// const TCP_HDR_LEN: usize = mem::size_of::<tcphdr>();
+    ///
+    /// #[repr(C)]
+    /// pub struct Buf {
+    ///    pub buf: [u8; 1500],
+    /// }
+    ///
+    /// #[map]
+    /// pub static mut BUF: PerCpuArray<Buf> = PerCpuArray::with_max_entries(1, 0);
+    ///
+    /// fn try_classifier(ctx: SkBuffContext) -> Result<i32, i32> {
+    ///     let buf = unsafe {
+    ///         let ptr = BUF.get_ptr_mut(0).ok_or(TC_ACT_PIPE)?;
+    ///         &mut *ptr
+    ///     };
+    ///     let offset = ETH_HDR_LEN + IP_HDR_LEN + TCP_HDR_LEN;
+    ///     ctx.load_bytes(offset, &mut buf.buf).map_err(|_| TC_ACT_PIPE)?;
+    ///
+    ///     // do something with `buf`
+    ///
+    ///     Ok(TC_ACT_PIPE)
+    /// }
+    /// ```
+    #[inline(always)]
+    pub fn load_bytes(&self, offset: usize, dst: &mut [u8]) -> Result<usize, c_long> {
+        if offset >= self.len() as usize {
+            return Err(-1);
+        }
+        let len = cmp::min(self.len() as isize - offset as isize, dst.len() as isize);
+        // The verifier rejects the program if it can't see that `len > 0`.
+        if len <= 0 {
+            return Err(-1);
+        }
+        // This is only needed to ensure the verifier can see the upper bound.
+        if len > dst.len() as isize {
+            return Err(-1);
+        }
+        let ret = unsafe {
+            bpf_skb_load_bytes(
+                self.skb as *const _,
+                offset as u32,
+                dst.as_mut_ptr() as *mut _,
+                len as u32,
+            )
+        };
+        if ret == 0 {
+            Ok(len as usize)
+        } else {
+            Err(ret)
+        }
+    }
+
     #[inline]
     pub fn store<T>(&mut self, offset: usize, v: &T, flags: u64) -> Result<(), c_long> {
         unsafe {