Skip to content
This repository has been archived by the owner on Jul 11, 2023. It is now read-only.

Error Loading BPF program #359

Open
sebastiaoamaro opened this issue Jan 3, 2023 · 5 comments
Open

Error Loading BPF program #359

sebastiaoamaro opened this issue Jan 3, 2023 · 5 comments

Comments

@sebastiaoamaro
Copy link
Contributor

Hi,
I am trying to load this BPF program, however, I get the error:
thread 'tokio-runtime-worker' panicked at 'error loading BPF program: LoadError("measure_tcp_lifetime", BPF)',
In RedBPF as far as I am aware tracks to this block

let cstr = unsafe { CStr::from_ptr(log_buffer) };

This is the code in the program

#![no_std]
#![no_main]
use core::mem::{self, MaybeUninit};
use memoffset::offset_of;

use redbpf_probes::socket_filter::prelude::*;

use monitor::usage::{SocketAddr,message};

//map to hold perf_events
#[map(link_section = "maps")]
static mut perf_events: PerfMap<message> = PerfMap::with_max_entries(512);

//map to hold the bytes sent
#[map(link_section = "maps")]
static mut usage: HashMap<u32, u128> = HashMap::with_max_entries(4096);

//map to hold time that has passed
#[map(link_section = "maps")]
static mut time: HashMap<u32, u64> = HashMap::with_max_entries(4096);

program!(0xFFFFFFFE, "GPL");
#[socket_filter]
fn measure_tcp_lifetime(skb: SkBuff) -> SkBuffResult {
    let eth_len = mem::size_of::<ethhdr>();
    let eth_proto = skb.load::<__be16>(offset_of!(ethhdr, h_proto))? as u32;
    if eth_proto != ETH_P_IP {
        return Ok(SkBuffAction::Ignore);
    }

    let ip_proto = skb.load::<__u8>(eth_len + offset_of!(iphdr, protocol))? as u32;
    if ip_proto != IPPROTO_TCP {
        return Ok(SkBuffAction::Ignore);
    }

    let mut ip_hdr = unsafe { MaybeUninit::<iphdr>::zeroed().assume_init() };
    ip_hdr._bitfield_1 = __BindgenBitfieldUnit::new([skb.load::<u8>(eth_len)?]);
    if ip_hdr.version() != 4 {
        return Ok(SkBuffAction::Ignore);
    }
    //Retrieve IPs from skbuff
    let ihl = ip_hdr.ihl() as usize;
    let dst = SocketAddr::new(
        skb.load::<__be32>(eth_len + offset_of!(iphdr, daddr))?,
        skb.load::<__be16>(eth_len + ihl * 4 + offset_of!(tcphdr, dest))?,
    );
    //We send new values every 25 milli seconds for a given ip, via perf_events
    unsafe{
        //retrieve size of packet
        let len:u128 = ((*skb.skb).len).into();
        let currenttime = bpf_ktime_get_ns();
        match time.get(&dst.addr){
            None=>{
                time.set(&dst.addr,&currenttime);
            },
            Some(oldtime)=>{
                if currenttime-oldtime > 25000000{
                //if currenttime-oldtime > 0{
                    match usage.get(&dst.addr){
                        None => usage.set(&dst.addr,&len),
                        Some(value) =>{
                            let newvalue:u128 = value + len;
                            usage.set(&dst.addr,&newvalue);
                            perf_events.insert(skb.skb as *mut __sk_buff,&message {dst:dst.addr,bytes:newvalue,}, );
                            time.set(&dst.addr,&currenttime);
                        }
                    }   
                }else{
                    match usage.get(&dst.addr){
                        None => usage.set(&dst.addr,&len),
                        Some(value) =>{
                            let newvalue:u128 = value + len;
                            usage.set(&dst.addr,&newvalue);
                        }
                    }
                }
            }
        }
    }

    Ok(SkBuffAction::Ignore)
}

I previously managed to get this program correctly loaded when I used u32 instead of u128, however, I need to change it now.
Is there anything related to u128 that the kernel does not allow?
Thank you in advance.

@rsdy
Copy link
Collaborator

rsdy commented Jan 4, 2023

That's correct, you can't use 128 bit wide fields in eBPF code. Should you need that, I think you will need to model it using 4 32 bit-wide fields.

@sebastiaoamaro
Copy link
Contributor Author

Hi, thanks for the quick reply!
And what about u64 are they allowed?

@rsdy
Copy link
Collaborator

rsdy commented Jan 9, 2023

@sebastiaoamaro I don't believe they are permitted either. The best way would be to test.

@sebastiaoamaro
Copy link
Contributor Author

I am gonna test this when I have the time I think it is interesting to know.
Should the cargo bpf tool allow the declaration of u128 if they are not allowed in the kernel? Do not know if this is hard to implement but it could maybe give a warning or something.
Thanks for the replies.

@bendahl
Copy link

bendahl commented May 3, 2023

@sebastiaoamaro,
@rsdy,

I think this depends on the kernel version. I've certainly used u128 in maps when dealing with IPv6 addresses. This patch set also suggests that support for 128 bit integers was added some time ago: https://www.spinics.net/lists/netdev/msg544476.html. For reference, I'm using a Kernel version 5.19 and have also performed some testing on 5.10. Hope this helps.

Cheers,
Ben

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants