Skip to content

Writing a BESS Configuration Script

Justine Sherry edited this page Feb 16, 2017 · 29 revisions

Once you know how to use bessctl, you know how to interact with BESS. So far, you've configured BESS by telling it to load some built-in BESS sample scripts. This page will tell you how to write your own configuration scripts.

Looking Inside a Script

First let's look at a familiar configuration script: samples/acl. From the bess/ main directory, the file is stored in bess/bessctl/conf/samples/acl.bess; go ahead and open it in your editor of choice (which we presume is vim if you are a cool person).

Here's what you will see: import scapy.all as scapy import socket

def aton(ip):
     return socket.inet_aton(ip)

# Craft a packet with the specified IP addresses
def gen_packet(proto, src_ip, dst_ip):
    eth = scapy.Ether(src='02:1e:67:9f:4d:ae', dst='06:16:3e:1b:72:32')
    ip = scapy.IP(src=src_ip, dst=dst_ip)
    udp = proto(sport=10001, dport=10002)
    payload = 'helloworld'
    pkt = eth/ip/udp/payload
    return str(pkt)

packets = [gen_packet(scapy.UDP, '172.16.100.1', '10.0.0.1'),
           gen_packet(scapy.UDP, '172.12.55.99', '12.34.56.78'),
           gen_packet(scapy.UDP, '172.12.55.99', '10.0.0.1'),
           gen_packet(scapy.UDP, '172.16.100.1', '12.34.56.78'),
           gen_packet(scapy.TCP, '172.12.55.99', '12.34.56.78'),
           gen_packet(scapy.UDP, '192.168.1.123', '12.34.56.78'),
          ]

fw::ACL(rules=[{'src_ip': '172.12.0.0/16', 'drop': False}])

Source() -> Rewrite(templates=packets) -> fw -> Sink()

At first glance, a couple of things should become clear to you:

  • BESS scripts are really just Python programs with a few additional features glued in.
    • You can see how these additional features are glued in in bess/bessctl/sugar.py if you are super curious.
    • The key "sugar" features to know about: you can create modules by declaring module objects, you can connect modules to each other (connect their gates) using arrows -> (which represent unidirectional packet flow) and you can give a module a name by assigning a name with :: (like fw::ACL(... in the example above).
  • You can create packets in your script using scapy, which is a convenient packet-manipulation library in Python.
  • You can write functions, create lists, etc. all like in normal Python.

To understand what this script says in particular, really all the action is happening on the line Source() -> Rewrite(templates=packets) -> fw -> Sink()

Here we have a chain of four modules. Since we are not connected to any network interfaces or applications to give us "real traffic", this example creates all of its own packets using a Source() module. A Source() module creates literally empty packets with no data in them. With a -> we connect the output of Source() to the input of a Rewrite module. Rewrite is a module that takes in a parameter -- a packet "template" -- and Rewrite fills in all the packets that come in to it with a copy of one of the packet templates.

After the packets have been filled in with data, we send the packets to fw, our ACL. Recall above that we named our ACL module fw, so now we can reference it in Python by this name. When we instantiated fw, we gave ACL a parameter as well. By default, ACL drops all packets that comes in. However, we gave it a rule to allow through (drop:False) all packets where src_ip matches 172.12.0.0/16, so packets in this prefix will be allowed through. All of the packets that are allowed through by fw are passed (via another ->) to Sink(), which is just a module that deletes every packet that comes in to it. Once again, normally we would probably pass all of the traffic out on a port to an application or to a network interface, but since this is just an example we will just drop all of the traffic.

What is happening under the hood when I run a script?

Recall from the overview that bessd actually forwards the packets, and bessctl is just a program that tells bessd what to do.

When you declare a module object in Python (e.g., Sink(), fw::ACL(...parameters...)), bessctl tells bessd to create a Sink module inside bessd; this Sink module that runs inside bessd is actually implemented in C++! You can look at all of the implementations of all modules in bess/core/modules. Whenever you write a new module in C++, the bess build script will create corresponding objects in Python for you to use in bessctl. Whatever you tell the Python object to do will be sent to the C++ object in bessd. Similarly, whenever you declare a -> in Python connecting two Python objects, bessd will connect the C++ modules representing those same modules on the dataplane.

All of this magic glue between your Python script and the actual, running C++ code in bessd is achieved using protobufs and grpc.

You can read all of the commands and parameters for all built-in modules here.

Writing a new script

Using modules with multiple gates

Calling a function on a module

Metadata attributes vs. Packet Data

Configuring the BESS scheduler