123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- // Copyright 2015 Big Switch Networks, Inc
- // (Algorithms for uBPF helpers, originally in C)
- // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
- // (Translation to Rust, other helpers)
- //
- // Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
- // the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
- // copied, modified, or distributed except according to those terms.
- //! This module implements some built-in helpers that can be called from within an eBPF program.
- //!
- //! These helpers may originate from several places:
- //!
- //! * Some of them mimic the helpers available in the Linux kernel.
- //! * Some of them were proposed as example helpers in uBPF and they were adapted here.
- //! * Other helpers may be specific to rbpf.
- //!
- //! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
- //! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
- //! respect this convention.
- extern crate libc;
- use std::u64;
- use time;
- // Helpers associated to kernel helpers
- // See also linux/include/uapi/linux/bpf.h in Linux kernel sources.
- // bpf_ktime_getns()
- /// Index of helper `bpf_ktime_getns()`, equivalent to `bpf_time_getns()`, in Linux kernel, see
- /// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
- pub const BPF_KTIME_GETNS_IDX: u32 = 5;
- /// Get monotonic time (since boot time) in nanoseconds. All arguments are unused.
- ///
- /// # Examples
- ///
- /// ```
- /// use rbpf::helpers;
- ///
- /// let t = helpers::bpf_time_getns(0, 0, 0, 0, 0);
- /// let d = t / 10u64.pow(9) / 60 / 60 / 24;
- /// let h = (t / 10u64.pow(9) / 60 / 60) % 24;
- /// let m = (t / 10u64.pow(9) / 60 ) % 60;
- /// let s = (t / 10u64.pow(9)) % 60;
- /// let ns = t % 10u64.pow(9);
- /// println!("Uptime: {:#x} == {} days {}:{}:{}, {} ns", t, d, h, m, s, ns);
- /// ```
- #[allow(dead_code)]
- #[allow(unused_variables)]
- pub fn bpf_time_getns (unused1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
- time::precise_time_ns()
- }
- // bpf_trace_printk()
- /// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
- /// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
- pub const BPF_TRACE_PRINTK_IDX: u32 = 6;
- /// Prints its **last three** arguments to standard output. The **first two** arguments are
- /// **unused**. Returns the number of bytes written.
- ///
- /// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
- /// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
- ///
- /// # Examples
- ///
- /// ```
- /// use rbpf::helpers;
- ///
- /// let res = helpers::bpf_trace_printf(0, 0, 1, 15, 32);
- /// assert_eq!(res as usize, "bpf_trace_printf: 0x1, 0xf, 0x20\n".len());
- /// ```
- ///
- /// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
- ///
- /// The eBPF code needed to perform the call in this example would be nearly identical to the code
- /// obtained by compiling the following code from C to eBPF with clang:
- ///
- /// ```c
- /// #include <linux/bpf.h>
- /// #include "path/to/linux/samples/bpf/bpf_helpers.h"
- ///
- /// int main(struct __sk_buff *skb)
- /// {
- /// // Only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed.
- /// // See <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/trace/bpf_trace.c>.
- /// char *fmt = "bpf_trace_printk %llx, %llx, %llx\n";
- /// return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
- /// }
- /// ```
- ///
- /// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
- /// program is run.
- #[allow(dead_code)]
- #[allow(unused_variables)]
- pub fn bpf_trace_printf (unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
- println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
- let size_arg = | x | {
- if x == 0 {
- 1
- } else {
- (x as f64).log(16.0).floor() as u64 + 1
- }
- };
- "bpf_trace_printf: 0x, 0x, 0x\n".len() as u64
- + size_arg(arg3) + size_arg(arg4) + size_arg(arg5)
- }
- // Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>
- /// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
- /// each argument must be a `u64`.
- ///
- /// # Examples
- ///
- /// ```
- /// use rbpf::helpers;
- ///
- /// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
- /// assert_eq!(gathered, 0x1122334455);
- /// ```
- pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
- arg1.wrapping_shl(32) |
- arg2.wrapping_shl(24) |
- arg3.wrapping_shl(16) |
- arg4.wrapping_shl(8) |
- arg5
- }
- /// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
- /// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
- /// cases. Arguments 3 to 5 are unused.
- ///
- /// # Examples
- ///
- /// ```
- /// use rbpf::helpers;
- ///
- /// let val: u64 = 0x112233;
- /// let val_ptr = &val as *const u64;
- ///
- /// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
- /// assert_eq!(val, 0x2a2a2a2a2a3b0819);
- /// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
- /// assert_eq!(val, 0x112233);
- /// ```
- #[allow(unused_variables)]
- pub fn memfrob (ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
- for i in 0..len {
- unsafe {
- let mut p = (ptr + i) as *mut u8;
- *p ^= 0b101010;
- }
- }
- 0
- }
- // TODO: Try again when asm!() is available in stable Rust.
- // #![feature(asm)]
- // #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
- // #[allow(unused_variables)]
- // pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
- // unsafe {
- // asm!(
- // "mov $0xf0, %rax"
- // ::: "mov $0xf1, %rcx"
- // ::: "mov $0xf2, %rdx"
- // ::: "mov $0xf3, %rsi"
- // ::: "mov $0xf4, %rdi"
- // ::: "mov $0xf5, %r8"
- // ::: "mov $0xf6, %r9"
- // ::: "mov $0xf7, %r10"
- // ::: "mov $0xf8, %r11"
- // );
- // }
- // 0
- // }
- /// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
- /// unused.
- ///
- /// # Examples
- ///
- /// ```
- /// use rbpf::helpers;
- ///
- /// let x = helpers::sqrti(9, 0, 0, 0, 0);
- /// assert_eq!(x, 3);
- /// ```
- #[allow(dead_code)]
- #[allow(unused_variables)]
- pub fn sqrti (arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
- (arg1 as f64).sqrt() as u64
- }
- /// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
- ///
- /// # Examples
- ///
- /// ```
- /// use rbpf::helpers;
- ///
- /// let foo = "This is a string.".as_ptr() as u64;
- /// let bar = "This is another sting.".as_ptr() as u64;
- ///
- /// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
- /// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
- /// ```
- #[allow(dead_code)]
- #[allow(unused_variables)]
- pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
- // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
- if arg1 == 0 || arg2 == 0 {
- return u64::MAX;
- }
- let mut a = arg1;
- let mut b = arg2;
- unsafe {
- let mut a_val = *(a as *const u8);
- let mut b_val = *(b as *const u8);
- while a_val == b_val && a_val != 0 && b_val != 0 {
- a +=1 ;
- b +=1 ;
- a_val = *(a as *const u8);
- b_val = *(b as *const u8);
- }
- if a_val >= b_val {
- (a_val - b_val) as u64
- } else {
- (b_val - a_val) as u64
- }
- }
- }
- // Some additional helpers
- /// Returns a random u64 value comprised between `min` and `max` values (inclusive). Arguments 3 to
- /// 5 are unused.
- ///
- /// Relies on `rand()` function from libc, so `libc::srand()` should be called once before this
- /// helper is used.
- ///
- /// # Examples
- ///
- /// ```
- /// extern crate libc;
- /// extern crate rbpf;
- /// extern crate time;
- ///
- /// unsafe {
- /// libc::srand(time::precise_time_ns() as u32)
- /// }
- ///
- /// let n = rbpf::helpers::rand(3, 6, 0, 0, 0);
- /// assert!(3 <= n && n <= 6);
- /// ```
- #[allow(dead_code)]
- #[allow(unused_variables)]
- pub fn rand (min: u64, max: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
- let mut n = unsafe {
- (libc::rand() as u64).wrapping_shl(32) + libc::rand() as u64
- };
- if min < max {
- n = n % (max + 1 - min) + min;
- };
- n
- }
|