Controller - UofG-netlab/BPFabric GitHub Wiki

Overview

The controller is a centralised application that accepts connections from the switches and using the Southbound API emits requests to the switches and receive requests from the switches.

The controller is logically centralised but to avoid a single point of failure multiple controllers can operate in the network and through a distributed database the state share amongst all of them to have a logically centralised and physically distributed controller.

The controller is necessary to install and configure function, however once installed the connection to the controller is not necessary and the switch will continue operating even if the connection to the controller is terminated.

The controller can send the following requests, see the switch documentation to see how each request is processed:

  • Hello
  • FunctionAddRequest
  • FunctionRemoveRequest
  • FunctionListRequest
  • TablesListRequest
  • TableListRequest
  • TableEntryGetRequest
  • TableEntryInsertRequest
  • TableEntryDeleteRequest
  • PacketOut

And processes the following event requests from the agent:

  • Hello
  • PacketIn
  • Notify

Framework

As part of BPFabric a simple python framework has been provided to allow any controller function to be implemented.

A custom controller can be implemented by extending the eBPFCoreApplication class. This class will perform the Hello handshake with the switch and nothing else. It is your responsibility to install the functions when necessary, update the tables if needed and react to incoming PacketIn and Notify events. Event handlers can be registered using the @set_event_handler decorator.

Example of a basic controller that only install the learning switch function a index 0 of the pipeline on handshake

from core import eBPFCoreApplication, set_event_handler, FLOOD
from core.packets import *

class LearningSwitchApplication(eBPFCoreApplication):
    @set_event_handler(Header.HELLO)
    def hello(self, connection, pkt):
        self.mac_to_port = {}

        with open('../examples/learningswitch.o', 'rb') as f:
            print("Installing the eBPF ELF")
            connection.send(FunctionAddRequest(name="learningswitch", index=0, elf=f.read()))

if __name__ == '__main__':
    LearningSwitchApplication().run()

This example controller waits for the Hello event from the switch, once received it loads the learningswitch.o eBPF program from disk and send a FunctionAddRequest for the function named learningswitch at index 0 in the pipeline.

You can react to Notify events emitted by the switches using the following snippet. connection will identify the switch that emitted the notification and pkt will be the notification event with an id for the event and some data.

    @set_event_handler(Header.NOTIFY)
    def notify_event(self, connection, pkt):
        print(pkt.id, pkt.data.encode('hex'))

Finally you can react to PacketIn events similarly. For instance if the pipeline emits a CONTROLLER action the packet will be handled by the handler below. In this example the getPort function is responsible for finding on which port this packet should be sent and resent the packet to the switch to be transmitted.

    @set_event_handler(Header.PACKET_IN)
    def packet_in(self, connection, pkt):
        connection.send(PacketOut(data=pkt.data, out_port=getPort(pkt)))

CLI

A Command Line Interface controller is provided that can send all the requests defined in BPFabric Southbound API except PacketOut. The CLI can be useful to test controller logic and inspect the state of the switches by listing the functions and tables installed in the switch.

The logic for PacketIn and Notify is specific to the function installed and requires a controller designed to support those messages. The CLI will not perform any action on receiving one of those event but will print in hexadecimal the packet or notification received.

The mapping between CLI command and Southbound API request is the following:

CLI Southbound API Example
<dpid> list FunctionListRequest() 1 list
<dpid> add <index> <name> <path> FunctionAddRequest(name, index, elf) 1 add 0 learningswitch ../examples/learningswitch.o
<dpid> remove <index> FunctionRemoveRequest(index) 1 remove 0
<dpid> table <index> list TablesListRequest 1 table 0 list
<dpid> table <index> <table_name> list TableListRequest(index, table_name) 1 table 0 inports list
<dpid> table <index> <table_name> get hex:key TableEntryGetRequest(index, table_name, key) 1 table table 0 inports get 00e0b45aadd5
<dpid> table <index> <table_name> update hex:key hex:value TableEntryInsertRequest(index, table_name, key, value) 1 table 0 inports update 00e0b45aadd6 01
<dpid> table <index> <table_name> delete hex:key TableEntryDeleteRequest(index, table_name, key) 1 table 0 inports delete 00e0b45aadd6
⚠️ **GitHub.com Fallback** ⚠️