-
Notifications
You must be signed in to change notification settings - Fork 445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
p4c-ubpf: new uBPF back-end for p4c #2134
Conversation
I took a quick look at the PR, it looks pretty good. I don't know if we can setup Travis to run Vagrant, DPDK and all the other stuff necessary for your tests. If we can, we should add your tests to the continuous integration, otherwise it's very easy for them to get broken by some random commit elsewhere. For just the compiler tests we could add your files to testdata/p4_16_samples, like we do with the ebpf tests (I am assuming they can be compiled with p4test); we could also suffix all your test programs with something like -ubpf.p4, which would make it easy for the test scripts to pick up only your tests for running them. We can leave your test programs where they are as well, but then it would still be nice for I will start reviewing your contribution, but it may take a while. Perhaps I will submit multiple reviews so you can start addressing the issues one by one. |
I also assume that you are committing to maintaining this implementation and fixing bugs that people may report for the foreseeable future. |
Ok. We will work to integrate our tests with existing test suite. We'll take a look at how it is done for ebpf and, then, prepare a separate commit.
Definitely! We devote some time to maintaining |
Just to be clear, I think what Mihai is proposing is to split the testing into:
- Compile-only tests, which can be run whether or not the backend is installed
- uBPF-specific tests, which would run if the backend were installed
Cheers,
-N
On Sat, Jan 11, 2020 at 10:16 AM Tomek Osiński <[email protected]<mailto:[email protected]>> wrote:
Ok. We will work to integrate our tests with existing test suite. We'll take a look at how it is done for ebpf and, then, prepare a separate commit.
I also assume that you are committing to maintaining this implementation and fixing bugs that people may report for the foreseeable future.
Definitely! We devote some time to maintaining p4c-ubpf.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub<#2134?email_source=notifications&email_token=AAOCFUQNTRZC23SQNEGTWILQ5HPF7A5CNFSM4KFJABPKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIWEBBY#issuecomment-573325447>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AAOCFUQ7DTQ5DUXV56OWVV3Q5HPF7ANCNFSM4KFJABPA>.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will continue reviewing in a separate comment.
Your testing infrastructure is very good.
backends/ubpf/README.md
Outdated
This repository implements the uBPF (Userspace BPF) backend for the P4 compiler (https://github.com/p4lang/p4c). | ||
|
||
The **p4c-ubpf** compiler allows to translate P4 programs into the uBPF programs. We use the uBPF implementation provided | ||
by [the Oko/P4rt-OVS switch](https://github.com/Orange-OpenSource/oko/tree/p4rt-ovs). The Oko's uBPF VM is based on the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this a fork of ovs? Do you expect that this fork will be merged within OvS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, this is a fork of OVS. I presented the details at OVSCon 19' [1]. There are no official plans to merge it with OVS yet. It is still a research prototype, but once it will be mature enough we can consider to propose such a contribution to OVS.
However, as far as I know, P4rt-OVS is the only switch to test uBPF back-end.
backends/ubpf/docs/EXAMPLES.md
Outdated
- `key_type` - is bit array type (i.e. bit<32>) or struct like type | ||
- `number_of_elements` - the maximum number of key-value pairs | ||
|
||
Currently registers have a limitation - they are not being initialized with default values. Initialization has to be done by a control plane. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P4 does not have a way to initialize registers, but your architecture can allow it if you want.
If there is a way in your architecture to initialize registers to default values before the start of the program you can promise this to your users. But at least for the in-kernel bfp I don't think there is a way to do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We analyzed different design options to initialize BPF maps (P4 registers) before the start of the program. And we decided that intializing them from a control plane is the best option for the moment. We could think about better approach later.
backends/ubpf/docs/EXAMPLES.md
Outdated
|
||
This is very simple example of stateful firewall. Every TCP packet is analyzed to track the state of the TCP connection. | ||
If the traffic belongs to known connection it is passed. Otherwise, it is dropped. | ||
Notice that the example program uses hash function which is constrained to hash only 64 bit values - that's why TCP connection is identified via IP source and destination address. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make it clear: this is a constraint that you have chosen. In P4 you could even declare a generic hash<T>(in T data)
which works for any P4 datatype.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that's the limitation of our implementation. In particular, it is the limitation of the ubpf_hash()
helper that we use to compute hash value. Also, to be improved in the future.
filter<H, M> filt, | ||
deparser<H> dprs); | ||
|
||
extern void mark_to_drop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest documenting these functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In particular, for mark_to_drop() and mark_to_pass(), what is the default behavior after a packet is done processing? Probably pass?
Then if the P4 program does mark_to_drop() and/or mark_to_pass() calls, whichever one was last determines whether the packet is passed or dropped later?
And there are no user-visible P4 variables that are modified by mark_to_drop() or mark_to_pass()? I would not ask, except this was an issue for several years with v1model's mark_to_drop(), and why it was changed to take a parameter later. It appears you have nothing that corresponds to standard_metadata, so it would make sense if in your architecture, mark_to_drop() and mark_to_pass() only modify state "hidden from the user's P4 program" inside the architecture implementation.
Another good thing to document about these extern functions is which of the architecture's parsers/controls they are allowed to be called in, e.g. maybe you intended something like "mark_to_drop() and mark_to_pass() may only be called in the filter control".
Comments in the p4include/v1model.p4 file would be good to look at for examples. If any of them happen to match the behavior you provide (e.g. that might be true for your Register extern compared to v1model's register extern), feel free to copy and paste whatever is accurate for your architecture.
# Install clang-10 | ||
if ! type "/vagrant/llvm-project/build/bin/clang" > /dev/null; then | ||
cd /vagrant | ||
git clone https://github.com/P4-Research/llvm-project |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so you have your own clone of llvm as well?
it would be nice to use an off-the-shelf version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, we are aware of that.
This is related to the limitation of BPF itself. It was also discussed in regards of p4c-xdp [1]. As we are in the userspace, we can simply increase the BPF's stack size. However, it requires to have a new flag in clang
compiler (this is also on our TODO list), as proposed in this thread [2].
Currently, we have our fork of clang
/ llvm, in which the stack size is increased and hardcoded.
[1] vmware-archive/p4c-xdp#22
[2] http://lists.llvm.org/pipermail/cfe-users/2017-March/001126.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be some code duplication with the ebpf back-end, but I don't think it will be easy to fix that.
Ideally your code should have subclassed the various ebfp classes and reused most methods that can be resued, but I understand that this is very difficult if you want to make any changes in the base classes.
It's probably OK to have the code duplication, although some bugs may need to be fixed multiple times.
I can't promise that I read every line very carefully, because there are lots of them, but hopefully your testing will cover the gaps that I had in my reading.
I will request some changes, although we could probably merge as it is an do the changes later too.
public: | ||
const UBPFControl *control; | ||
std::set<const IR::Parameter *> toDereference; | ||
std::vector<cstring> saveAction; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add a comment explaining this field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to be the last action executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used to implement action_run
. It stores the action that was executed. This approach is based on and taken from p4c-ebpf
.
@mbudiu-vmw thank you for your comments! I'll address them soon. We also started to prepare compile-only tests. Currently, in parallel, we work on a demo showcase for our internal purposes, so it grabs us a part of time and we cannot work intensively on PR, sorry for that! |
I've just submitted a small commit (with some minor modifications) addressing some of your comments. In particular, there was some code, which was useless, but remained in the files. The rest of comments we will address in the next week. |
@@ -0,0 +1,358 @@ | |||
/* Automatically generated by p4c-ubpf from /home/mateusz/p4c/testdata/p4_16_samples/ipv4-actions_ubpf.p4 on Mon Jan 20 15:27:07 2020 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to save these files in the repository?
Are you comparing with them in some tool?
The ebpf back-end does not save the C files - I was afraid that they would change too often with compiler changes to make for good tests, but perhaps that's wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're it is not the best way, but I think it is the only reasonable (at least for now) way to test if the C files generated by p4c-ubpf
are correct. We compare them at very basic level, using a minimalistic Python code.
We are aware that it could require changes to these file once we will add some new functionality to p4c-ubpf
. I would keep these files for now, until we will integrate P4rt-OVS (or some other uBPF verifier) with make check-ubpf
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've removed these files and replaced them by userspace-only tests (based on those implemented for ebpf
)
@mbudiu-vmw I think we addressed most of your comments. Build was successful and all tests passed. There are two actions on our TODO list for next days:
I'll update you once we will implement this two features. |
@mbudiu-vmw Could you guide me how to replicate test environment of Travis locally? I'm running tests locally and they are passed, but once I push them to master, Travis-generated tests fail. I use |
You have 3 failures in your Travis tests: https://travis-ci.org/p4lang/p4c/jobs/649504069?utm_medium=notification&utm_source=github_status |
* Registers, get_timestamp extern, rate limiter example. * Remove unnecessary includings. * Move register class to separated file and other small fixes.
Take size of table from P4 code.
…itional nullptr check in UBPFDeparser.
…rol') by removing dead code
@mbudiu-vmw Finally, we've made all modifications and tests are passed. I think we can move on with review and merge. |
🚀 |
Great, I will try to review it next week. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't re-read all the code, I mostly checked to see whether the comments from the previous review have been addressed. I think we can merge this.
} | ||
|
||
void UbpfTarget::emitUbpfHelpers(EBPF::CodeBuilder *builder) const { | ||
builder->append( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks a bit brittle. Is there a guarantee that the numbers associated with these functions will never change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a strict requirement, which is specific to target that we use (P4rt-OVS). Perhaps, it could be generalized in the future, but at the moment the BPF program would not work otherwise.
} else if (auto block = s->to<IR::BlockStatement>()) { | ||
convertActionBody(&block->components); | ||
continue; | ||
} else if (s->is<IR::ReturnStatement>()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to put here a BUG_CHECK that no return or exit is encountered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I shouldn't put BUG_CHECK here, because retrun or exit could be encountered here (as both exit and return are allowed for actions according to specs). However, we use this else if
block to implement a proper behavior, i.e. don't emit any statements following exit or return.
Since there are no other comments I will go ahead and merge this huge PR. |
Yay! |
This PR implements the uBPF (Userspace BPF) backend for the P4 compiler
The
p4c-ubpf
compiler allows to translate P4 programs into the uBPF programs.The backend for uBPF is mostly based on p4c-ebpf, but generates the C code, which is compatible with the user space BPF implementation. Moreover, it has support for P4 registers and programmable actions (packet's modifications + tunneling).
We tested
p4c-ubpf
with the Oko switch [1], but the uBPF Virtual Machine can be used in any software switch implementing the kernel bypass (e.g. DPDK apps).Basic usage:
[1] https://github.com/Orange-OpenSource/oko/tree/p4rt-ovs