Home

Awesome

BEHAVIORAL MODEL (bmv2)

Build Status

This is the second version of the reference P4 software switch, nicknamed bmv2 (for behavioral model version 2). The software switch is written in C++17. It takes as input a JSON file generated from your P4 program by a P4 compiler and interprets it to implement the packet-processing behavior specified by that P4 program.

This repository contains code for several variations of the behavioral model, e.g. simple_switch, simple_switch_grpc, psa_switch, etc. See here for more details on the differences between these.

bmv2 is not meant to be a production-grade software switch. It is meant to be used as a tool for developing, testing and debugging P4 data planes and control plane software written for them. As such, the performance of bmv2 - in terms of throughput and latency - is significantly less than that of a production-grade software switch like Open vSwitch. For more information about the performance of bmv2, refer to this document.

Installing bmv2

Installing packaged versions of bmv2

bmv2 has package support for several Ubuntu and Debian distributions.

Ubuntu

A bmv2 package is available in the following repositories for Ubuntu 20.04 and newer.

. /etc/os-release
echo "deb http://download.opensuse.org/repositories/home:/p4lang/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/home:p4lang.list
curl -fsSL "https://download.opensuse.org/repositories/home:p4lang/xUbuntu_${VERSION_ID}/Release.key" | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/home_p4lang.gpg > /dev/null
sudo apt update
sudo apt install p4lang-bmv2

Debian

For Debian 11 (Bullseye) it can be installed as follows:

echo 'deb http://download.opensuse.org/repositories/home:/p4lang/Debian_11/ /' | sudo tee /etc/apt/sources.list.d/home:p4lang.list
curl -fsSL https://download.opensuse.org/repositories/home:p4lang/Debian_11/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/home_p4lang.gpg > /dev/null
sudo apt update
sudo apt install p4lang-bmv2

If you cannot use a repository to install bmv2, you can download the .deb file for your release and install it manually. You need to download a new file each time you want to upgrade bmv2.

  1. Go to https://build.opensuse.org/package/show/home:p4lang/p4lang-bmv2, click on "Download package" and choose your operating system version.

  2. Install bmv2 by running the command below with the corresponding path where the package was downloaded.

sudo dpkg -i /path/to/package.deb

Installing bmv2 from source

  1. Clone the git repository.

    git clone https://github.com/p4lang/behavioral-model.git
    
  2. Install build dependencies. You can find specific instructions for Ubuntu 20.04 and Fedora below.

    Ubuntu 20.04

    sudo apt-get install -y automake cmake libgmp-dev \
        libpcap-dev libboost-dev libboost-test-dev libboost-program-options-dev \
        libboost-system-dev libboost-filesystem-dev libboost-thread-dev \
        libevent-dev libtool flex bison pkg-config g++ libssl-dev
    

    You also need to install the following from source. Feel free to use the install scripts under ci/.

    Fedora

    sudo dnf install -y automake cmake gmp-devel libpcap-devel \
        boost-devel boost-system boost-thread boost-filesystem boost-test \
        libevent-devel libtool flex bison pkg-config g++ openssl-devel \
        thrift-devel nanomsg-devel
    

    To use the CLI, you will need to install the nnpy Python package. Feel free to use ci/install-nnpy.sh.

    To make your life easier, we provide the install_deps.sh script, which will install all the dependencies needed on Ubuntu 20.04.

    Our CI tests now run on Ubuntu 20.04.

    On MacOS you can use the tools/macos/bootstrap_mac.sh script to install all the above dependencies using homebrew. Note that in order to compile the code you need XCode 8 or later.

  3. Building the code

    ./autogen.sh
    ./configure
    make
    sudo make install  # if you need to install bmv2
    

    In addition, on Linux, you may have to run sudo ldconfig after installing bmv2, to refresh the shared library cache.

    Debug logging is enabled by default. If you want to disable it for performance reasons, you can pass --disable-logging-macros to the configure script.

    In 'debug mode', you probably want to disable compiler optimization and enable symbols in the binary:

     ./configure 'CXXFLAGS=-O0 -g'
    

    The new bmv2 debugger can be enabled by passing --enable-debugger to configure.

Running the tests

To run the unit tests, simply do:

make check

If you get a nanomsg error when running the tests (make check), try running them as sudo

Running your P4 program

To run your own P4 programs in bmv2, you first need to compile the P4 code into a json representation which can be consumed by the software switch. This representation will tell bmv2 which tables to initialize, how to configure the parser, ...

There are currently 2 P4 compilers available for bmv2 on p4lang:

Assuming you have installed the p4c compiler, you can obtain the json file for a P4_16 v1model program as follows:

p4c --target bmv2 --arch v1model --std p4-16 <prog>.p4

This will create a <prog>.json output file which can now be 'fed' to the bmv2 simple_switch binary:

sudo ./simple_switch -i 0@<iface0> -i 1@<iface1> <prog>.json

In this example <iface0> and <iface1> are the interfaces which are bound to the switch (as ports 0 and 1).

Using the CLI to populate tables...

The CLI code can be found at tools/runtime_CLI.py. It can be used like this:

./runtime_CLI.py --thrift-port 9090

The CLI connect to the Thrift RPC server running in each switch process. 9090 is the default value but of course if you are running several devices on your machine, you will need to provide a different port for each. One CLI instance can only connect to one switch device.

The CLI is realized using the Python's cmd module and supports auto-completion. If you inspect the code, you will see that the list of supported commands. This list includes:

- table_set_default <table name> <action name> <action parameters>
- table_add <table name> <action name> <match fields> => <action parameters> [priority]
- table_delete <table name> <entry handle>

The CLI include commands to program the multicast engine. Because we provide 2 different engines (SimplePre and SimplePreLAG), you have to specify which one your target is using when starting the CLI, using the --pre option. Accepted values are: None, SimplePre (default value) and SimplePreLAG. The l2_switch target uses the SimplePre engine, while the simple_switch target uses the SimplePreLAG engine.

You can take a look at the commands.txt file for l2_switch and simple_router to see how the CLI can be used.

Using the debugger

To enable the debugger, make sure that you passed the --enable-debugger flag to configure. You will also need to use the --debugger command line flag when starting the switch.

Use tools/p4dbg.py as follows when the switch is running to attach the debugger to the switch:

sudo ./p4dbg.py [--thrift-port <port>]

Displaying the event logging messages

To enable event logging when starting your switch, use the --nanolog command line option. For example, to use the ipc address ipc:///tmp/bm-log.ipc:

sudo ./simple_switch -i 0@<iface0> -i 1@<iface1> --nanolog ipc:///tmp/bm-log.ipc <path to JSON file>

Use tools/nanomsg_client.py as follows when the switch is running:

sudo ./nanomsg_client.py [--thrift-port <port>]

The script will display events of significance (table hits / misses, parser transitions, ...) for each packet.

Loading shared objects dynamically

Some targets (simple_switch and simple_switch_grpc) let the user load shared libraries dynamically at runtime. This is done by using the target-specific command-line option --load-modules, which takes as a parameter a comma-separated list of shared objects. This functionality is currently only available on systems where dlopen is available. Make sure that the shared objects are visible by the dynamic loader (e.g. by setting LD_LIBRARY_PATH appropriately on Linux). You can control whether this feature is available by using --enable-modules / --disable-modules when configuring bmv2. By default, this feature is enabled when dlopen is available.

Integrating with Mininet

We will provide more information in a separate document. However you can test the Mininet integration right away using our simple_router target.

In a first terminal, type the following:

- cd mininet
- sudo python3 1sw_demo.py --behavioral-exe ../targets/simple_router/simple_router --json ../targets/simple_router/simple_router.json

Then in a second terminal:

- cd targets/simple_router
- ./runtime_CLI < commands.txt

Now the switch is running and the tables have been populated. You can run pingall in Mininet or start a TCP flow with iperf between hosts h1 and h2.

When running a P4 program with simple_switch (instead of simple_router in the above example), just provide the appropriate simple_switch binary to 1sw_demo.py with --behavioral-exe.

FAQ

Why is throughput so low / why are so many packets dropped?

bmv2 is not meant to be a production-grade software switch. For more information on bmv2 performance, please refer to this document.

Why did we replace p4c-behavioral with bmv2?

How do program my own target / switch architecture using bmv2?

You can take a look at the targets/ directory first. We have also started writing some doxygen documentation specifically targetted at programmers who want to implement their own switch model using the bmv2 building blocks. You can generate this documentation yourself (if you have doxygen installed) by running doxygen Doxyfile. The output can be found under the doxygen-out directory. You can also browse this documentation online.

What else is new in bmv2?

Are all features supported yet?

At this time, we are aware of the following unsupported P4_14 features:

If you find more missing features or if you would like to request that a specific feature be added, please send us an email (p4-dev@lists.p4.org) or submit an issue with the appropriate label on Github. Do not hesitate to contribute code yourself!

How do I signal a bug?

Please submit an issue with the appropriate label on Github.

How can I contribute?

See CONTRIBUTING.md.