Skip to content
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

Merged
merged 60 commits into from
Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
ecd39c0
Initial phase of implementing the p4c-ubpf compiler
osinstom Apr 8, 2019
ec22005
Adding support for UBPF parser
osinstom Apr 8, 2019
a687110
UBPF Parser - first implementation
osinstom Apr 13, 2019
75fdcf6
The UBPF parser implemented
osinstom Apr 14, 2019
2fcdcf8
UBPF initial control block.
kmateuszssak Apr 17, 2019
acfaa6e
Working Ubpf control block.
kmateuszssak May 6, 2019
99d6854
Change ubpf table name.
kmateuszssak May 6, 2019
78335fa
Small fixes
osinstom May 13, 2019
93643c2
Remove accept parameter from reference model.
kmateuszssak May 13, 2019
118b2b2
Change table key names.
kmateuszssak May 13, 2019
884c40a
Change table key names v2.
kmateuszssak May 13, 2019
d57742f
Some fixes to the p4c-ubpf + docs
osinstom May 21, 2019
dcf0903
Copyright headers added
osinstom May 21, 2019
3d64116
Update README.md
osinstom Jul 4, 2019
9231f53
Packet modifications support
osinstom Jul 16, 2019
dbb237e
Take size of table from P4 code.
kmateuszssak Aug 8, 2019
1090527
registers_support (#4)
kmateuszssak Aug 7, 2019
c0bc2c5
Merge pull request #5 from P4-Research/master2
osinstom Aug 8, 2019
0df4fa5
hash (#6)
kmateuszssak Sep 30, 2019
5a86d96
Refactor #include + Fix registers read (#7)
kmateuszssak Oct 1, 2019
b96fcca
Generate p4info
kmateuszssak Sep 30, 2019
b880030
Support for P4 metadata
osinstom Oct 1, 2019
3089cbb
Fix after p4info merge. Add semicolon after enum declaration.
kmateuszssak Oct 2, 2019
edcbb1d
Change max nr of table entries to 2^27 because of errors while loadin…
kmateuszssak Oct 4, 2019
cfaa628
Change ubpf_model filename, code cleaning
osinstom Oct 7, 2019
5cc9931
Adding tunneling support + PTF tests (#13)
kmateuszssak Dec 19, 2019
c63a939
p4c-ubpf doesn't compile after sync with master; fix build dependenci…
osinstom Dec 20, 2019
322f5c1
Uncomment ebpf_enable in CmakeLists.txt.
kmateuszssak Jan 7, 2020
1adffa0
T202: Update oko (p4rt-ovs) repository address and refactor scripts (…
kmateuszssak Jan 9, 2020
b3eb458
T207: Revert p4info support in p4c (temporary solution) (#15)
kmateuszssak Jan 10, 2020
5893f22
T208: Remove changes in ebpf p4c backend (#16)
kmateuszssak Jan 10, 2020
0ca94d3
T210: Review p4c once again (#17)
osinstom Jan 10, 2020
085294b
Addressing review comments: minor modifications to P4 programs and sc…
osinstom Jan 17, 2020
8ab0e2a
Compile-only tests + code cleanup
kmateuszssak Jan 20, 2020
302d279
Add not committed before symbolic links
kmateuszssak Jan 21, 2020
381d4ee
Fix symbolic links
kmateuszssak Jan 21, 2020
e4330a8
Remove dependencies on scapy in run-ubpf-test.py
osinstom Jan 21, 2020
1fd859e
Documentation for architecture model + code cleanup
osinstom Jan 28, 2020
08b7de0
Remove dependencies on BMv2 helpers.h
osinstom Jan 28, 2020
b8b3f06
Refactor of hash() generation. Generate tuple from Type_List.
osinstom Jan 24, 2020
e22ad6f
Remove useless code
kmateuszssak Jan 24, 2020
38acee5
Move metadata to tests
kmateuszssak Jan 24, 2020
c648326
Path expression code refactor
kmateuszssak Jan 24, 2020
c5c324e
Add check register type
kmateuszssak Jan 24, 2020
7f0b72e
Refactor method to generate register read()
osinstom Jan 28, 2020
2b6020c
Small fixes to test scripts and UBPFRegister
osinstom Jan 29, 2020
997d5db
Refactor pointer variables' handling in UBPFControl/UBPFRegister. Add…
osinstom Jan 29, 2020
db6c4db
Fix build error (invalid use of incomplete type 'class UBPF::UBPFCont…
osinstom Jan 29, 2020
2e12ee3
Refactor Exit and Return statement's handling
osinstom Jan 30, 2020
6bc8674
Implement checksum computation
osinstom Feb 3, 2020
7ec6f33
Optimizations of test environment installation script
osinstom Feb 7, 2020
2be7ec7
Add missing test file
osinstom Feb 7, 2020
b1479ad
Refactor check of packet's length in Parser
osinstom Jan 30, 2020
668e808
User-space only tests (#18)
osinstom Feb 12, 2020
6ae22e4
Fix p4c-ubpf error.
kmateuszssak Feb 18, 2020
cc59b0d
Fix test errors related to frontend
osinstom Feb 19, 2020
fb07d84
Register read refactor (#19)
kmateuszssak Feb 20, 2020
daad335
Macro redefinition
kmateuszssak Feb 20, 2020
f5bcc01
Update travis.yml to exclude ubpf tests for OSx
osinstom Feb 20, 2020
89eb992
Small code refactor and update of docs
osinstom Feb 25, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Adding tunneling support + PTF tests (#13)
Adding tunneling support + PTF tests
  • Loading branch information
kmateuszssak committed Feb 14, 2020
commit 5cc9931b5f124fa4108f65fdad2406825841de03
3 changes: 3 additions & 0 deletions backends/ubpf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ set(P4C_UBPF_SOURCES
ubpfBackend.cpp
ubpfProgram.cpp
ubpfParser.cpp
ubpfDeparser.cpp
ubpfControl.cpp
ubpfType.cpp
ubpfTable.cpp
Expand All @@ -40,9 +41,11 @@ set(P4C_UBPF_SOURCES
../../backends/ebpf/lower.cpp)

set(P4C_UBPF_HEADERS
codeGen.h
ubpfProgram.h
ubpfType.h
ubpfParser.h
ubpfDeparser.h
ubpfControl.h
ubpfRegister.h
ubpfModel.h
Expand Down
10 changes: 6 additions & 4 deletions backends/ubpf/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Introduction to uBPF Backend

This is a back-end, which generates the code to be consumed by the userspace BPF VM - https://github.com/iovisor/ubpf .
This repository implements the uBPF (Userspace BPF) backend for the P4 compiler (https://github.com/p4lang/p4c).
osinstom marked this conversation as resolved.
Show resolved Hide resolved

The P4-to-uBPF compiler accepts only the P4_16 programs written for the `ubpf_filter_model.p4` architecture model.
The **p4c-ubpf** compiler allows to translate P4 programs into the uBPF programs. We use the uBPF implementation provided by [the ubpf project](https://github.com/iovisor/ubpf).

The P4-to-uBPF compiler accepts only the P4_16 programs written for the `ubpf_model.p4` architecture model.
osinstom marked this conversation as resolved.
Show resolved Hide resolved

The backend for uBPF is mostly based on [P4-to-eBPF compiler](../ebpf/README.md). In fact, it implements the same concepts, but
generates the C code, which is compatible with the user-space BPF implementation.
Expand Down Expand Up @@ -68,8 +70,8 @@ The output file (`out.o`) can be injected to the uBPF VM.

### Known limitations

* The modification of wide packet's fields has not been tested extensively. Hence, it can not work properly.

* No support for some P4 constructs (meters, counters, etc.)
* No support for checksum computation.
osinstom marked this conversation as resolved.
Show resolved Hide resolved

### Contact

Expand Down
20 changes: 20 additions & 0 deletions backends/ubpf/codeGen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef P4C_CODEGEN_H
#define P4C_CODEGEN_H

#include "lib/sourceCodeBuilder.h"
#include "ebpf/codeGen.h"
#include "target.h"

namespace UBPF {
class UbpfCodeBuilder : public EBPF::CodeBuilder {
public:
const UbpfTarget *target;

explicit UbpfCodeBuilder(const UbpfTarget *target) : EBPF::CodeBuilder(target), target(target) {

}
};
}


#endif //P4C_CODEGEN_H
130 changes: 101 additions & 29 deletions backends/ubpf/docs/EXAMPLES.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Introduction

This file contains description of the basic P4 programs, which were used to test the functionality of the P4-to-uBPF compiler.
All tests have been run on the [Oko](https://github.com/Orange-OpenSource/oko) switch using the [Vagrant prepared for Oko](https://github.com/P4-Research/vagrant-oko).
All tests have been run on the [Oko](https://github.com/Orange-OpenSource/oko) switch using [Vagrant prepared for Oko](https://github.com/P4-Research/vagrant-oko).

Before any experiment the following commands need to be invoked:

Expand All @@ -10,14 +10,19 @@ Before any experiment the following commands need to be invoked:
$ p4c-ubpf -o test.c PROGRAM.p4
$ sudo ovs-ofctl del-flows br0
# compile test.c to BPF machine code
$ clang-3.8 -O2 -I .. -target bpf -v -c test.c -o /tmp/test.o
# Load filter BPF program and setup rules to forward traffic
$ sudo ovs-ofctl load-filter-prog br0 1 /tmp/test.o
$ sudo ovs-ofctl add-flow br0 table=1,ip,nw_dst=172.16.0.12,actions=output:1
$ sudo ovs-ofctl add-flow br0 priority=1,in_port=2,filter_prog=1,actions=goto_table:1
$ sudo ovs-ofctl add-flow br0 in_port=1,filter_prog=1,actions=output:2
$ clang-6.0 -O2 -I .. -target bpf -c test.c -o /tmp/test.o
# Load filter BPF program
$ sudo ovs-ofctl load-bpf-prog br0 1 /tmp/test.o
# Setup rules to forward traffic (bidirectional)
$ sudo ovs-ofctl add-flow br0 in_port=2,actions=prog:1,output:1
$ sudo ovs-ofctl add-flow br0 in_port=1,actions=prog:1,output:2
```

**Note!** The P4-uBPF compiler and Oko work properly with `clang-6.0`. We noticed some problems when using older versions of clang (e.g. 3.9).

# Examples

This section presents how to run and test the P4-uBPF compiler.

## Packet modification

Expand All @@ -43,15 +48,15 @@ This section presents P4 program, which modifies the packet's fields.
Sample usage:

```bash
$ sudo ovs-ofctl update-map br0 1 0 key 14 0 16 172 value 0 0 0 0 0 0 0 0 0 0 0 0 # decrements MPLS TTL
$ sudo ovs-ofctl update-map br0 1 0 key 14 0 16 172 value 1 0 0 0 24 0 0 0 0 0 0 0 # sets MPLS label to 24
$ sudo ovs-ofctl update-map br0 1 0 key 14 0 16 172 value 2 0 0 0 24 0 0 0 0 0 0 0 # sets MPLS label to 24 and decrements TTL
$ sudo ovs-ofctl update-map br0 1 0 key 14 0 16 172 value 3 0 0 0 3 0 0 0 0 0 0 0 # modifies MPLS TC (set value to 3)
$ sudo ovs-ofctl update-map br0 1 0 key 14 0 16 172 value 4 0 0 0 24 0 0 0 1 0 0 0 # sets MPLS label to 24 and TC to 1
$ sudo ovs-ofctl update-map br0 1 0 key 14 0 16 172 value 5 0 0 0 1 0 0 0 0 0 0 0 # modifies stack value of MPLS header
$ sudo ovs-ofctl update-map br0 1 0 key 14 0 16 172 value 6 0 0 0 6 0 0 0 0 0 0 0 # changes IP version to 6.
$ sudo ovs-ofctl update-map br0 1 0 key 14 0 16 172 value 7 0 0 0 0 0 0 0 0 0 0 0 # swaps IP addresses
$ sudo ovs-ofctl update-map br0 1 0 key 14 0 16 172 value 8 0 0 0 1 0 16 172 0 0 0 0 # sets source IP address to 172.16.0.1
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 0 0 0 0 0 0 0 0 0 0 0 0 # decrements MPLS TTL
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 1 0 0 0 24 0 0 0 0 0 0 0 # sets MPLS label to 24
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 2 0 0 0 24 0 0 0 0 0 0 0 # sets MPLS label to 24 and decrements TTL
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 3 0 0 0 3 0 0 0 0 0 0 0 # modifies MPLS TC (set value to 3)
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 4 0 0 0 24 0 0 0 1 0 0 0 # sets MPLS label to 24 and TC to 1
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 5 0 0 0 1 0 0 0 0 0 0 0 # modifies stack value of MPLS header
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 6 0 0 0 6 0 0 0 0 0 0 0 # changes IP version to 6.
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 7 0 0 0 0 0 0 0 0 0 0 0 # swaps IP addresses
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 8 0 0 0 1 0 16 172 0 0 0 0 # sets source IP address to 172.16.0.1
```

### IPv6 (oko-test-ipv6.p4)
Expand All @@ -67,22 +72,24 @@ The match key is source IPv6 address. The P4 program implements three actions:
Sample usage:
```bash
# Changes destination IPv6 address from fe80::a00:27ff:fe7e:b95 to e00::: (simple, random value)
$ sudo ovs-ofctl update-map br0 1 0 key 254 128 0 0 0 0 0 0 10 0 39 255 254 21 180 17 value 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 254 128 0 0 0 0 0 0 10 0 39 255 254 21 180 17 value 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
# Swaps source and destination IPv6 addresses
$ sudo ovs-ofctl update-map br0 1 0 key 254 128 0 0 0 0 0 0 10 0 39 255 254 21 180 17 value 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 254 128 0 0 0 0 0 0 10 0 39 255 254 21 180 17 value 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
# Sets Flow Label to 1.
$ sudo ovs-ofctl update-map br0 1 0 key 254 128 0 0 0 0 0 0 10 0 39 255 254 21 180 17 value 2 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 254 128 0 0 0 0 0 0 10 0 39 255 254 21 180 17 value 2 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
```

## Registers

This section presents P4 program, which uses registers.
This section presents P4 programs, which use registers.
Register can be declared this way:
`Register<value_type, key_type>(number_of_elements) register_t;`
where:
`value_type` - is bit array type (i.e. bit<32>) or struct like type
`key_type` - is bit array type (i.e. bit<32>) or struct like type
`number_of_elements` - the maximum number of key-value pairs
`number_of_elements` - the maximum number of key-value pairs

Currently registers have a limitation - they are not being initialized automatically. Initialization has to be done by control plane.

### Rate limiter (rate-limiter.p4)

Expand All @@ -94,21 +101,86 @@ For instance now BUCKET_SIZE has value of 10 and WINDOW_SIZE has value of 100.
It means that 10 packets are passed in 100 ms window. It also means 100 packets per second.
If you send 1470 Bytes width packets the bit rate should not exceed 1.176 Mbit/s (1470B * 8 * (10/100ms)).

For measuring the bandwidth use for instance iperf:
Due to registers limitation before starting your own tests initialize rate limiter registers with zeros:
```bash
# Initalizes timestamp_r register
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 0 0 0 0 value 0 0 0 0
# Initalizes count_r register
$ sudo ovs-ofctl update-bpf-map br0 1 1 key 0 0 0 0 value 0 0 0 0
```

For measuring the bandwidth use for instance iperf tool:

Start a iperf UDP server
```
iperf -s -u
```bash
$ iperf -s -u
```
Then run iperf client
```
iperf -c <server_ip> -b 10M -l 1470
```bash
$ iperf -c <server_ip> -b 10M -l 1470
```

### Rate limiter (rate-limiter-structs.p4)

The same rate limiter as above but implemented with structs.
The same rate limiter as above, but implemented using structs.

### Simple firewall

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.
Copy link
Contributor

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.

Copy link
Contributor Author

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.


Due to registers limitation before starting your own tests initialize simple firewall registers with zeros:
```bash
# Initalizes conn_state register (key is a output from a hash function for client(192.168.1.10) and server (192.168.1.1))
$ sudo ovs-ofctl update-bpf-map br0 1 0 key 172 192 20 5 value 0 0 0 0
# Initalizes conn_srv_addr register (key is a output from a hash function for client(192.168.1.10) and server (192.168.1.1))
$ sudo ovs-ofctl update-bpf-map br0 1 1 key 172 192 20 5 value 0 0 0 0
```

To test simple firewall you can use as an example `ptf/stateful_test.py` test.

## Tunneling

This section presents more complex examples of packet tunneling operations. There are two P4 programs used:

* `tunneling.p4`, which implements MPLS tunneling,
* `vxlan.p4`, which implements more complex packet tunneling: VXLAN.

### VXLAN

To run example compile `vxlan.p4` with `p4c` and then `clang-6.0`.

Sample usage:
```bash
# Sets action vxlan_decap() (value 0) for packets matching rule VNI=25 (key 25)
# handled by the table upstream_tbl (map id 0) and BPF prog 1.
sudo ovs-ofctl update-bpf-map br0 1 0 key 25 0 0 0 value 0 0 0 0
# Sets action vxlan_encap() (value 0) for packets matching rule IP dstAddr=172.16.0.14 (key 14 0 16 172)
# handled by the table downstream_tbl (map id 1) and BPF prog 1.
sudo ovs-ofctl update-bpf-map br0 1 1 key 14 0 16 172 value 0 0 0 0
```

### GPRS Tunneling Protocol (GTP)

To run example compile `gtp.p4` with `p4c` and then `clang-6.0`.

To test encapsulation:
```bash
# For downstream_tbl (ID 1) sets action gtp_encap() (value 0) and GTP TEID=3 for packets with destination IP address 172.16.0.14.
$ sudo ovs-ofctl update-bpf-map br0 10 1 key 14 0 16 172 value 0 0 0 0 3 0 0 0
```

To test decapsulation:
```bash
# For upstream_tbl (ID 0) sets action gtp_decap() for packets matching GTP TEID=3.
$ sudo ovs-ofctl update-bpf-map br0 10 0 key 3 0 0 0 value 0 0 0 0
```

## Counters
Scapy can be used to easily test GTP protocol:

TBD
```python
>>> load_contrib('gtp')
>>> p = Ether(dst='08:00:27:7e:0b:95', src='08:00:27:15:b4:11')/IP(dst='172.16.0.14', src='172.16.0.12')/UDP(sport=2152,dport=2152)/GTPHeader(teid=3)/IP(dst='172.16.0.14', src='172.16.0.12')/ICMP()
>>> sendp(p, iface='eth1')
```
Loading