rust-bpf / rust-bcc

user-friendly rust bindings for the bpf compiler collection
MIT License
475 stars 54 forks source link

Infinite loops when iterating over BPF tables #198

Open Deputation opened 1 year ago

Deputation commented 1 year ago

I encountered an issue related to the iteration of BPF table entries, which resulted in an infinite loop. The loop continually processes the table going over it and restarting from the start without ever really stopping.

The issue arises during the iteration of BPF entries in a table using table.iter(). In the loop, the same entries seem to be processed repeatedly, leading to an infinite loop and prohibiting the iteration from reaching its expected end.

Faulty code snippet:

let mut bpf_entries: Vec<FilterRules> = Vec::new();

eprintln!("Starting to iterate BPF entries");
for entry in table.iter() {
    eprintln!("Processing a BPF entry");
    unsafe {
        let rule: FilterRules = ptr::read_unaligned(entry.key.as_ptr() as *const _);
        bpf_entries.push(rule);
    }
}
eprintln!("Finished processing BPF entries");

I anticipated that the iterator would process each entry in the BPF table exactly once, eventually reaching the end of the table and exiting the loop. If this is not the expected behavior (as the examples of the library would imply) this issue can simply be closed.

Workaround:

let mut bpf_entries: Vec<FilterRules> = Vec::new();
let mut seen_entries: std::collections::HashSet<Vec<u8>> = std::collections::HashSet::new();

eprintln!("Starting to iterate BPF entries");
for entry in table.iter() {
    eprintln!("Processing a BPF entry");
    unsafe {
        if seen_entries.contains(&entry.key) {
            eprintln!("Duplicate BPF entry found. Exiting loop.");
            break;
        }

        seen_entries.insert(entry.key.clone());
        let rule: FilterRules = ptr::read_unaligned(entry.key.as_ptr() as *const _);
        bpf_entries.push(rule);
    }
}
eprintln!("Finished processing BPF entries");

I would greatly appreciate clarification on whether the described behavior is expected or if it might be a potential bug. Specifically, is the iterator designed to restart from the beginning of the entries after each loop, or should it progress through each entry once and subsequently exit the loop?

brayniac commented 1 year ago

@Deputation - I believe the correct behavior would be to iterate through the table entries once and return None.

I'd suggest taking a look at libbpf-rs instead of this crate though.

brayniac commented 1 year ago

I'd happily accept a PR that fixes this and publish a new version of the crate. But I've migrated to libbpf-rs so there's not much active focus on these crates right now.