alexforster / pdu

Small, fast, and correct L2/L3/L4 packet parser.
https://crates.io/crates/pdu
Apache License 2.0
56 stars 9 forks source link

inlining for use with bpf/xdp? #1

Open alexeldeib opened 4 years ago

alexeldeib commented 4 years ago

Hi! πŸ‘‹ I'm exploring using Rust to write bpf programs, and this package is a great fit for some of the networking usecases like xdp. I also found https://github.com/uccidibuti/rebpf/blob/37775452ca79b7c232d535e8c989f07d751a612e/examples/basic03_map_counter/src/kern.rs#L40-L57 which is a reflection of https://github.com/xdp-project/xdp-tutorial/tree/master/basic03-map-counter, and noticed rebpf is based on libbpf-sys which you also maintain πŸ˜„ thanks for the quality libraries.

If you look at the first link from rebpf, that example can't import pdu because it runs in a bpf context which requires function inlining for non-bpf code. This crate already works for no_std which is great. I've tested that slapping #[inline] everywhere makes some of the basics work properly in bpf programs.

Would you consider a cargo feature or some other method of inlining every function so the crate can be used easily from bpf programs? Alternatively if you have some experience with this, do you know an easier approach to use pdu in that context?

I'm happy to help prepare a PR if you're on board, but I wasn't sure what the best approach would be other than manually adding conditional #[inline] everywhere (proc macro of some sort)?

Appreciate your thoughts πŸ˜ƒ

alexforster commented 4 years ago

I didn't even realize rebpf was using this, cool!

I'd love for this crate to work for your usecase, but let me ask around and see if there's a better way than annotating everything with #[inline].

alexforster commented 4 years ago

Hi! Sorry for going dark. I just pushedΒ a branch: https://github.com/alexforster/pdu/tree/inline

I asked/googled around and found that the following things are true:

So I had to use the brute-force method of applying #[inline] to every function in the crate. The closest I got to a cleaner solution was the apply_attr crate, but it is unmaintained per regexident/apply_attr#2 (cc @uccidibuti – have you found a better way?)

Before I publish a new release, please try the branch when you get the chance and let me know how it works out.

[dependencies]
pdu = { git = "https://github.com/alexforster/pdu", branch = "inline", default-features = false, features = ["inline"] }
uccidibuti commented 4 years ago

I'm working from some days to add a "bpf" features (in cargo.toml) to pdu, I want use pdu to parse packet in bpf programs with rebpf.. adding inline to all functions (I have made it with a simple bash script) in pdu is not enough because for some reason: 1) when you run a bpf programs the bpf verifier reject it if before access to packet address you don't check explicitly (with a if condition) that the address is less then maximum packet address (you must check the packet address and not the buffer length) .. 2) pdu use Rust std slice method that they call some inline(never) methods and then llvm compiler doesn't link these method correctly.. 3) For 1), we need remove all "while" condition when we use pdu with "bpf" features.. I have already fix 1 and 2 and I'm working to fix also 3) and to rewrite rebpf example to parse packet using pdu. Monday I will back to home and i will push my progress in my pdu fork, I hope to complete all before the next weekend but i you help me maybe we can do it before..

alexforster commented 4 years ago

Oh cool, I'll defer to your branch then. I haven't used rebpf (clearly), but in general the verifier is the thing I was most concerned about, because we definitely jump backwards during IP and TCP options parsing and IPv6 extension header parsing. It's going to be tough to unroll those.

alexeldeib commented 4 years ago

So I had to use the brute-force method

That was about where I was when I opened the issue πŸ˜„ Since then I ran into a few issues which I could tell were related to the verifier, but wasn't yet sure why

we need remove all "while" condition when we use pdu with "bpf" features

that probably explains it, I was looking for bounds checks on array index but didn't consider loops very closely!

I'm working from some days to add a "bpf" features (in cargo.toml) to pdu... but if you help me maybe we can do it before

I'll take a look at your branch and see if I can find a good place to jump in πŸ‘

uccidibuti commented 4 years ago

Sorry for my later but i was busy with my work.. This is an example of bpf programs that parse ipv4 and mac address using rebpf + my fork of pdu: packet_parser

To do this I have added a bpf feature in my fork of pdu, I don't kwnow if this is a right way to add bpf support in pdu of if there is a better solution, @alexforster let me know what do you think about my solution, if you want I can do a pull request to pdu inline branch. Note1: currently my fork support bpf feature only for ethernet and ipv4.. Note2: adding packet address check and inline attribute in pdu (this is what i did) is not sufficient to to parse packet in bpf programs because pdu use sliceIndex methods that call some inline(never) functions. So to fix this problem I have made a bash scripts build.sh and remove_undefined_functions.sh that remove the undefined called from llvm bytecode before convert llvm bytecode into bpf code.. I know this is not a very elegant solution but is the only solution that i found.. If you are a better solution let me know..