UofG-netlab / BPFabric

BPFabric implementations. Details about this work are available in the research paper "BPFabric: Data Plane Programmability for Software Defined Networks" published at ANCS 2017
https://netlab.dcs.gla.ac.uk
30 stars 15 forks source link

Enable tunneling/encapsulation #1

Open mscastanho opened 6 years ago

mscastanho commented 6 years ago

Hi, I wanted to use BPFabric to create a switch capable of performing encapsulation using a custom-made protocol. For this to happen, I would need to add a new protocol header between existing headers (ex. after Ethernet and before IP). But by the examples provided I'm actually having a hard time figuring out how I could accomplish that.

I know I can get the packet's length from the packet's metadata. From there, I would need to allocate a new buffer to fit the original packet + the new header (since there probably won't be enough space left in the original buffer). But from this point on, I don't see a way to pass this new buffer back to the switch so this new modified packet is sent.

Is it even possible? If so, what are my options? Could I make any changes to the source code to allow this?

Thank you in advance.

simon-jouet commented 6 years ago

Hi @mscastanho,

The tunneling/encapsulation is not implemented in the current version of BPFabric, that was something planned for a future phase. However getting it implemented is probably fairly straightforward.

Are you using the softswitch implementation or the DPDK implementation? In either case the easiest approach would be to define a new function available in BPF to push or pop a header from the front of the packet and then implement it in the softswitch or DPDK.

In DPDK it would likely be a call to something like rte_pktmbuf_prepend to allocate some space at the front of the packet (on push) and rte_pktmbuf_adj (on pop).

In the softswitch implementation the implementation would likely allocate/remove some space after/before the ethernet header (at the moment the frame is metadata + ethernet and when sending the metadata is stripped away https://github.com/UofG-netlab/BPFabric/blob/master/softswitch/main.c#L332)

mscastanho commented 6 years ago

Thanks for the prompt response @simon-jouet,

I'm working on the changes as of now. For now I'll be focusing on the softswitch. It took me a while to get around the code, but now I'm starting to grasp it. These are the steps I'm planning on taking to implement it:

_ebpffunctions.h

  1. Add _bpfpush and _bpfpop operations to _ebpffunctions.h

    softswitch/main.c

  2. Create a structure to hold data length (push/pop) and pointer (push) if we need to perform either operation on the next packet.

  3. Implement functions _bpfpush and _bpfpop , which fill the pushpop structure with appropriate data to be checked later by function transmit.

  4. Inside transmit, before checking the port, check pushpop struct to check whether a push/pop request was made for this packet. If pop, increase data pointer by pushpop.len. If push, allocate more space and copy the data pointed by pushpop.data to the new free space. If nothing, continue normally.

  5. Still inside transmit, after packet transmission, clear pushpop data so next packet don't get changed inadvertently.

A few questions, though:

  1. Am I on the right track? Does anything seem off?
  2. I will need to pass pointers to _bpfpush and _bpfpop to the agent as well, right? From what I saw, the agent is the one who actually registers the bpf functions on the ubpf vm to allow code generation when programs are installed later.
  3. To perform a push, I think I'll probably need to allocate new memory dynamically with a bigger length to fit the new header + packet and pass this new data down to be transmitted. I don't really like this idea, since dynamic allocation + data copying will probably affect performance, but I don't see a way around it. Is there a better way?

Thank you again

simon-jouet commented 6 years ago

Hi @mscastanho

  1. Looks like you're on the right track :). You might also need to add some extra checks depending on the size of the data you want to send (no to excess 1 MTU)

  2. Yes you would just to register it (https://github.com/UofG-netlab/BPFabric/blob/master/agent/agent.c#L554) . The main reason for that is that in BPFabric the dataplane shouldn't really be aware of BPF, just run the appropriate dataplane function and use the returned value to make a forwarding decision

  3. Each frame in the ring is 2048bytes already so it's likely that you will have enough space already without the need to reallocate (well depending on what you want to add but I very much doubt it will be many bytes) https://github.com/UofG-netlab/BPFabric/blob/master/softswitch/main.c#L85

mscastanho commented 6 years ago

Hi @simon-jouet

I successfully implemented the functionality, sorry for not returning earlier.

I might make a pull request in the following weeks, after I test it a little bit further and make sure it is fully functional.

Thank you for the help!

pezaros commented 6 years ago

That's good to hear, @mscastanho - well done!

It would be good if you had any performance figures / testing of your module to feed back - e.g., any bench-marking or any comparative measurement against alternative ways of achieving the same thing. We have documented the other example programs we have tried in pp. 9-11 of the below: http://eprints.gla.ac.uk/138952/13/138952.pdf