p4c-ubpf - the new back-end for the P4 compiler!

NOTE: This blog post was originally published on P4.org: https://opennetworking.org/news-and-events/blog/p4c-ubpf-a-new-back-end-for-the-p4-compiler/.


With the constant development of the P4 language more and more programmable targets are emerging. The P4 compiler has already support for the next-generation Linux datapath such as eBPF/XDP. However, it is sometimes required to introduce runtime extensibility mechanism in a user-space packet processing applications. It can be achieved by using the user-space BPF (uBPF) Virtual Machine, which is a re-implementation of in-kernel eBPF VM and provides a user-space execution environment, which can be extended at runtime.

This blog post introduces p4c-ubpf - the new back-end for the P4 compiler - that enables programming packet processing modules for uBPF. The p4c-ubpf allows to execute the P4 code in any solution implementing the kernel bypass (e.g. DPDK or AF_XDP applications).

Userspace BPF for packet processing

Why uBPF?

The uBPF project [1] re-implements the eBPF kernel-based Virtual Machine. It contains eBPF assembler, disassembler, interpreter, and JIT compiler for x86-64. While the BPF programs are intented to be run in the kernel, the uBPF project enables running the BPF programs in user-space applications. Therefore, the uBPF Virtual Machine can be well-integrated with the kernel bypass (e.g. DPDK/AF_XDP) applications.

Moreover, contrary to the eBPF implementation, uBPF is not licensed under GPL. The uBPF implementation is licensed under Apache License, version 2.0. Finally, the userspace eBPF implements less complex virtual machine, so that some constructs are not supported (e.g. tail calls), but, on the other hand, the stack size of the uBPF program is not limited to 512 bytes.

P4rt-OVS

Open vSwitch (OVS) is a widely adopted high-performance programmable virtual switch. P4rt-OVS is an extension of Open vSwitch that integrates the BPF virtual machine with the userspace datapath of OVS. Hence, P4rt-OVS allows to extend the OVS packet processing pipeline without recompilation by injecting BPF programs at runtime. BPF programs act as programmable actions and they are referenced as a new OVS action (keyword prog) in the OpenFlow tables. Programmable actions are allowed to write to packets as well as read and write to persistent maps (hash tables) to retain information on flows.

Furthermore, a user can use the P4 language to develop new, protocol-independent data plane extensions (BPF programs) for Open vSwitch. P4 provides a high-level and declarative language, so writing a new network features becomes super easy! p4c-ubpf, the uBPF back-end for the P4 compiler, provides the architecture model to write P4 programs making use of wide range of P4 features including stateful registers.

Compiling P4 to uBPF

The P4-to-uBPF compiler follows the same convention as P4 compilers for eBPF or XDP backends, i.e. the P4 program is firstly translated to the C representation and, then, compiled to the BPF code using clang compiler. It makes things a little bit easier as P4 compiler does not need to generate low-level BPF instructions.

            ------------              ---------
P4_16 --->  | p4c-ubpf | ---> C ----> | clang | --> uBPF
            ------------              ---------

We designed a new architecture model for P4c-uBPF (depicted below). The ubpf_model architecture consists of a single parser, match-action pipeline, and deparser. We made the decision to disable packet forwarding in the first version, what simplifies the design, but can be treated as a limitation. It means it is the responsibility of the underlaying target to determine output port for incoming packets. P4rt-OVS is implemented according to this design principle. However, p4c-ubpf can be enhanced to support packet forwarding in the next releases.

p4c-ubpf-architecture-model.png

The p4c-ubpf compiler provides also a library of extern functions that implement features not supported by the P4 language. These functions can be called from the P4 program as a normal action. The ubpf architecture model supports such operations as hash functions, stateful registers, timestamp retrieving and checksum computation. To see the heavily commented, full specification of the architecture model see this link.

Translating P4 to C

The key operation that is performed by p4c-ubpf is translation from P4 to C. The following tables provide a brief summary of how each P4 construct is mapped to a corresponding C construct. Note that the translation is very similar to p4c-ebpf and p4c-xdp.

Translating parser

P4 Construct C Translation
header struct type with an additional valid bit
struct struct
parser state code block
state transition goto statement
extract load/shift/mask data from packet buffer

Translating match-action pipelines

P4 Construct C Translation
table eBPF map
table key struct type
table actions block tagged union with all possible actions
action arguments struct
table reads eBPF map’s lookups
action body code block
table apply switch statement
registers additional eBPF map
register reads eBPF map’s lookups
register writes eBPF map’s updates

Translating deparser

P4 Construct C Translation
apply block code block + adjusting packet’s size
emit operation header’s validity check + write/shift/mask data to packet buffer

p4c-ubpf vs. other BPF-related compilers

The uBPF is yet another BPF-related backend for P4. p4c-ebpf generates programs to be attached to the Linux TC subsystem, p4c-xdp targets XDP hook, while p4c-ubpf produces code to be run in at the user-space level. There are differences in the range of functionalities that these P4 backends support. The table below provides a brief comparison of features provided by each BPF-related backend.

Comparsion of features provided by p4c-ebpf, p4c-xdp and p4c-ubpf

Feature p4c-ebpf p4c-xdp p4c-ubpf
Packet filtering YES YES YES
Packet’s modifications & tunneling NO YES YES
Simple packet forwarding YES YES NO
Registers NO NO YES
Counters YES YES NO
Checksum computation NO YES YES

Summary

The uBPF backend for the P4 compiler can be used for any application that processes packets in a user space. It has already been used to implement various, simple applications such as stateful firewall, rate limiter or GTP tunneling. For instance, in case of P4rt-OVS, p4c-ubpf allows to implement network protocols, which are not currently supported by Open vSwitch. See this link for more examples.

We encourage community to start playing with uBPF backend, report bugs and propose new enhancements. For questions or comments, please send an email to tomasz.osinski2@orange.com.

Quick links

BPF and XDP Reference Guide

Background on P4 and eBPF

P4-uBPF - presentation from Open vSwitch and OVN Fall 2019 conference

P4rt-OVS - Github repository




    Enjoy Reading This Article?

    Here are some more articles you might like to read next:

  • Network prototyping made easy with P4 and Python!
  • Implementing tunneling techniques in P4 based on the example of VXLAN
  • OVS_AFXDP - step-by-step installation guide
  • My notes from podcast "Why doesn't OVS support P4?"
  • My takeways from the "C Traps and Pitfalls" book