Skip to content

sliceable_switch_tutorial

Kazuya Suzuki edited this page Apr 26, 2012 · 1 revision

Sliceable switch tutorial

A sliceable switch is a Trema application. But unlike most other Trema applications that read a static configuration file and emulate a network of virtual switches and hosts a sliceable switch doesn't emulate any network as such but listens passively for any packet-in events. It then restricts or permits packet-in frames based on forwarding rules read from SQLite database files updated dynamically by client users through a RESTful API. In essence it is an openflow controller functioning at data link layer.
In large networks to guarantee user security and facilitate traffic management requires that service providers isolate user traffic at layer 2. One way to achieve this is by assigning a VLAN-ID to each user. But as stated in IEEE 802.1Q a device can support a maximum of 4096 VLAN-IDs. Although a core switch is able to accommodate more traffic the VLAN limit imposes a restriction. The sliceable switch addresses this problem by introducing another level of redirection which is the slice concept. The slice notion imposes a traffic restriction. Unless the packet-in frame belongs to a registered slice access is denied. But on the other hand allows aggregation of disperse traffic to a slice that could represent a device entering/exiting an enterprise network. Further a user client can specify a set of header fields with wildcard fields to define a scope of flows associated with an action (allow, deny or redirect to local port). The scope can be further extended to include a datapath_id, slice, or even combination of both. A sliceable switch can be used to create a large scale service within a single domain or a service that spans multiple domains without considering mesh connectivity between the devices participating in the network. A single slice can be set up to connect two or more domains together. Overall this reduces signalling (packet-outs broadcasts) and saves network bandwidth therefore allowing large scale deployments. The sliceable switch depends on the services of two applications topology and topology discovery that send and receive LLDP packets to figure out port interconnections. When topology reports that it has discovered a port the sliceable switch adds the port to a list. When a port goes down the corresponding port is removed from the list. The sliceable switch relies on port statuses events to create a topological view of the network. An accurate topological view is crucial in order to resolve a path and set up flows for packet traversals.
The sliceable switch is basically a store and forward device. It creates a layer 2 domain that is capable of learning and forwarding on Ethernet addresses that is closed to a given set of users. When it receives a packet-in extracts the source MAC address and creates a mapping entry between the MAC address the datapath id and the port on which the packet-in was received.
In MAC-based VLAN setup a mobile host carries a unique MAC address associated with a VLAN-ID. This piece of information together with the datapath_id and ingress port used as key to locate the slice as a first step of authentication. To route the packet-in to destination the following steps are carried out by a forwarding process.

  1. Sliceable switch offers a more extensive level of authentication termed as filter. A filter is a pattern matcher with a number of patterns. It accepts an incoming packet-in with origin information (slice, datapath_id, ingress port), performs a match against each pattern and outputs an action depending on the outcome. Actions are simple instructions allow (green light), deny (red light) and local (yellow light redirect traffic). Users can add identical filter patterns and prioritize them using a priority field. Filter rules/patterns operate on packet attributes and on a much wider scope like slice and/or datapath_id. Filter's pattern matching is a two-stage process. First an attempt is made to locate an entry using exact matching, if not wildcard matching follows. An allow action signifies further processing (steps that follow) otherwise a flow is installed at source to temporary cease incoming traffic. For a local action to function properly the packet must be an IPv4 and the end result is a packet-out sent to source with modified layer 2 addresses.
  2. Using the destination MAC address the outgoing datapath_id + port searched in the forwarding database. Failing in finding a match the packet is flooded to each port to each virtual switch along the determined path. Knowing the datapath_id + port is enough to forward a packet-out to destination virtual switch but additional steps ensure that host pertaining information is validated as well.
  3. One way to address any host attached to a virtual switch is by assigning a unique VLAN-ID to a port. Step 3 attempts to find the outgoing VLAN-ID using the slice + datapath_id + port composite keys. The next step is only executed if no VLAN-ID match is found in the current step.
  4. This is case where a host is assigned a unique MAC address that is used to locate the egress slice. If the ingress and egress slices differ a flow would be installed at the virtual switch to discard and prevent the influx of packets-ins at the sliceable switch for a short interval. Otherwise a packet-out with action set to flood is sent to each virtual switch along the resolved path to ensure that the packet eventually would reach the destination. A path is resolved using the Dijkstra shortest path algorithm.

Access to Database

A sliceable switch uses a simple interface to SQLite store. At initialization it reads and loads into memory the SQLite store creating an up to date cache of the data. In the get accessor the cached value is returned. This cache is usually presented as a hash table to enable fast retrieval of data given a key store. To ensure that the in-memory cache is recent a periodic timer is installed that checks for any changes to the store files. The in-memory cache is refreshed when a change is detected. There is no provision to segregate individual changes to records and load only those changes without having to read the whole store. A sliceable switch would age and remove entries from the hash table. If the in-memory cache is reloaded previous aged entries become ineffective and need to be aged again. Also currently all registered flows would be invalidated/deleted from each vswitch.

Database tables

Slice

A slice table stores information pertaining to a slice. A slice record on its own has no special meaning nor it constitutes to any behavior unless it is associated with a binding. From this perspective a slice record can be thought as a container with a number of contained objects (bindings). A slice table contains the following fields:

  • number - a record number incremented by one when a new record is added. A client user doesn't have access to this field. This identifier always refers to the same record unless that record is deleted. It is possible while experimenting that a gap of unused record numbers created from a repeated number of deletions and additions that in the worse case scenario could impede new additions. In a such a rare case the number type should be increased to handle a wider range of numbers.
  • id - a distinct easy to remember slice identifier known to client users.
  • description - a descriptive name for a slice

The number and id fields are primary unique keys with database constraints to handle violation failures during save. The slice supports creating, updating, listing and deleting slice records without any transaction atomicity.

Bindings

A binding table stores a particular type of binding port or mac or a combination of both. It consists of the following fields:

  • type - the kind of binding.
  • datapath_id - an arbitrary value that identifies the vswitch. This same identifier is used in every OpenFlow message.
  • port - a physical port index into virtual switch's port list.
  • vid - a VLAN-ID assigned to a port.
  • mac - a source MAC address of either a host or a virtual switch.
  • id - a unique id created as a result of combining the datapath_id, port and VLAN-ID if not explicitly specified.
  • slice_number - a foreign key reference to id field of the slice table that is associated with.

A unique constraint is enforced on id and slice_number keys. The mac field would only have a valid value if a record of binding type mac or both port and mac is created. All database operations add delete and list supported except update.

Transient memory

Switches/ports

Sliceable switch relies on topology and topology_discovery applications to probe the network and report its state. As a result of this sliceable switch receives two kind of topology notifications - link and port. The link notification indicates connectivity between two adjacent nodes. A port a more frequent notification describes certain characteristics of a particular port and its state (UP/DOWN). Using this information sliceable switch creates in transient memory a linked list of vswitches and for each vswitch a "child" port linked list. The linked list interface provides the usual access methods (add, delete and search). Reported port states are always considered as valid and applied without any extra validation. This eases the burden of sliceable switch maintaining its own state. If a vswitch goes down the parent-child relationship is enforced to delete all port child objects prior to deleting the parent vswitch. Topological information is vital to resolve a path between two hosts and if not possible, a flow is installed to reject further packets from source for a specified interval.

Forwarding

During initialization sliceable switch creates a forwarding database. It is a transient hash to associate an Ethernet MAC address with a datapath_id and port number and housekeeping time stamp information. When a packet-in received a new hash entry is created with the vswitch identifier (datapath_id) and ingress port as values and source MAC address as key. A look up operation returns the datapath_id and port number based on key (Ethernet MAC address) search. A multicast or a broadcast MAC address is ignored during this process. The forwarding database also covers host mobility the case where a MAC address is found on a different port or another vswitch and will cease any bidirectional traffic from the old MAC address by registering flow-deletes. The forwarding also unlearns/deletes MAC entries with inactivity period of over 5 seconds. The aging timer for a MAC address should be reset when a packet with the same source MAC address is received. Therefore aging is important not only for conservation of memory but also for administration procedures as well.

Host db

A host db is a hash table and its storage organized as such that a source IPv4 address represents the key and a source MAC address, datapath_id and ingress port are the values. Those traffic characteristics are stored in the hash table before redirection to a pre-configured tun network interface occurs. The hash table is accessed again when the packet is read from the tun interface to decide if redirection should be proceeded. Entries from the hash table would be removed after the aging interval timer is honored.

Filter

A current snapshot constructed by reading the contents of SQLite store's filter database file. Data read organized in a composite structure consisting of a hash table to store exact match entries and a linked list to store wildcard entries. (see table below)

Filter table
hash table linked list
The hash table is indexed using extended match attributes. Extended match attributes include a datapath_id field and the slice_number field as well as the normal OpenFlow packet match attributes. A filter entry (see table below) encapsulates three pieces of information, the extended packet match attributes, a priority field and an action/policy field.
Filter entry
Key Openflow ofp-match
wildcards
in_datapath_id
slice nunber
Value priority
action

The priority field has a special meaning when adding or comparing filter entries. It is a mode to discriminate filter entries with same attributes but with different actions but only applicable to distinct wildcard values (non-exact match flows). A non-strict match combines the wildcard values for example w1 and w2 by oring them and conditional checking each field attribute. In a strict match instead both wildcard values must be equal and each field attribute must match. Filter entries remain permanent in memory unless a database modification is detected that would cause a full reload erasing the old data.

Slice

Reads the SQLite store slice file and creates a memory image of its data. This data is an aggregated presentation of hash tables, a table for each slice binding. A binding is a structure with fields accessible and available to every kind of binding. The kind of binding is set during record creation and can be either a port, a mac, or mac-based binding on ports. There is no real limitation on the number of bindings of any kind that can be created. The hash tables used here are no different to a well-known hash with a safeguard to prevent adding duplicate entries in order to maintain key-value uniqueness. Port-based bindings remain valid only for a certain period and would be deleted when this period expires. Most of the hash operations are self-explanatory but the look up slice is more complicate since it takes into consideration sliceable's switch operational mode. The look up slice takes a number of arguments and either returns the slice or a value that indicates that the slice is not found. One of the arguments is a source or a destination MAC address used as key in mac-based binding table while other arguments as the datapath_id, port and VLAN-ID used for searching port related bindings. Obvious a user is free to define any kind of binding possible resulting in multiple matches. Therefore a search order is imposed based on sliceable's switch operational mode (default, loose, restrict). The following sections describe the processing steps of look up slice in greater detail for different kind of arguments and prerequisites. For start lets assume the default operational mode is used and a port-based binding is set that matches all passed-in parameters. In detail the processing steps are:

  1. Attempt to locate a slice on MAC-based binding table.
  2. Since no slice found as expected, search on port-based binding table.
    • On success return the found slice.
    • Otherwise return an error code to the caller.

Of-course a slice would be found if a MAC-based binding is set which is faster since only one look up operation is performed.
Next lets assume that a MAC-based binding exists and loose mode is set. In this case the processing steps are:

  1. Locate the slice on MAC-based binding table.
    • On success return the found slice.
    • Otherwise return an error code to the caller.

Repeating the same test with default mode set we observe that a port-based binding is dynamically added as follows:

  1. Locate the slice on MAC-based binding table.
  2. Slice found. Attempt to locate the slice on port-binding table.
    • On success return the found slice.
    • Otherwise add a port-based binding and return the found slice.

For subsequent unknown or broadcast packets even if a MAC-based binding search returns false the slice number would be returned from the port-based binding table. Next the case where loose mode is set with only a port-based binding. The processing steps are:

  1. Locate the slice on MAC-based binding table.
  2. Since no slice found as expected, search on port-based binding table.
    • On success return the found slice.
    • Otherwise return an error code to the caller.

As can be seen the above steps are identical to default mode when port-based binding exists and setting to loose mode is of no particular benefit. Also in default mode a port-based binding is dynamically created when a match is found on mac-based binding table. This is interpreted to mean that any broadcast packet that arrives to that port would be flooded within the slice. Next lets examine the restrict mode. As a prerequisite we register a mac-based binding on ports which means we actually have two bindings. We expect that the mac-based binding on ports would take preference over the port-based binding. Lets verify the processing steps:

  1. Attempt to locate the slice on MAC-based binding table.
  2. Since no slice found as expected a search is made on mac-based binding on ports.
    • On success return the found slice.
    • Otherwise return an error code to the caller.

Although a slice is found it doesn't mean that the packet-in would be routed to target. Other governing rules may prohibit this from happening but this is not the subject of this section.

RESTful API Implemenation

Config.cgi is a perl program that implements a simple web server to process requests from client users to support the functionality of the sliceable API. The program doesn't provide any locking mechanism to prevent concurrent read/write access by multiple processes and relies on the SQLite store for any locking. It handles all RESTful CRUD operations on a recognized URI path for two target main objects networks and filters. All data sent to this program should be JSON serialized. For persistence storage it uses an SQLite store that reads and writes into two database files slice and filter. In the same directory where the config.cgi program resides a create_tables.sh script exists that creates the SQL tables for the above SQLite database files. The slice database file consists of two tables slices and bindings while the filter of only one table named filter. The script also creates a default filter entry to allow traffic from any source. To determine target object information the URI path is slash (“/”) separated into individual parts. The URI path may address the following objects:

  • Networks. The individual networks for example of each floor of each building.
  • Ports. A logical to physical port mapping described by a triplet of attributes (datapath_id, physical port, VLAN-ID).
  • Attachments. A way to attach a host to a network and make access control decisions taking into account the source MAC address.
  • Filters. Access control lists. Its scope covers not only packet attributes but other terms such as slice, datapath_id to provide a flexible configurable access control list.

Handle Get Requests

The purpose of the GET operation is to retrieve and return pre-created stored information about a particular object type. The last part of the URI designates the object type. Knowing the target object a specific query type is issued to database to retrieve all records. The response to a GET request on a collection resource (eg. networks) would return all the objects available in the database. In most cases a simple query without any conditional statement is sufficient to retrieve the desired data. But access to "leaf" objects such as ports and attachments require multiple queries to be issued. Database access errors such as unable to locate a keyed in record(s) are trapped and propagated to user client. On a successful retrieval the program loops through each record propagating a JSON array with the results. It is not considered an error to return an empty JSON array when no matching records found. The API supports no range parameters to retrieve a subset of records.
For example a curl request to read all networks might return the following:

curl -v http://127.0.0.1:8888/networks  
[{"id":"test-slice","description":"debugging section"}]  

Handle POST requests

A client user uses the POST operation on a target container object to create a child object underneath. The program config.cgi handles all POST requests in a similar fashion, parsing mandatory parameters setting values for any optional parameters and checking for duplicate keys before issuing an insert statement into database. At last a user client receives a result that reflects the success/failure code of the insert database transaction. As with the GET operation an attempt to create a child object under one or more parent container object instance succeeds only if all parent instances exist.
For example to create a network direct a POST request to the following end point.

POST http://127.0.0.1:8888/building-A/networks  

A curl request would look like this:

curl -v http://127.0.0.1:8888/building-A/networks -X POST -d '{ "id": "floor-1", "description": "marketing department" }' -H "Content-type: application/json"

Handle PUT requests

A client user uses the PUT operation on a specific target object to modify object properties. Prior knowledge of the object's modifiable properties is necessary to avoid processing errors. After modification the order of other existing objects should not be disturbed. As part of the update database operation, the object modifiable values are saved. An example of updating a network using JSON is given below:

PUT http://127.0.0.1:8888/building-A/networks/floor-1 
{
  "description": "marketing department"
}  

Handle DELETE requests

The URI syntax of a delete operation is identical to the get operation. A successful delete operation should delete the reference parent object and all its dependent children and can not be undone. It is not possible to issue a single delete command to remove container type objects for example networks, ports, attachments. Container objects can be removed by issuing a number of delete requests on single child object instances. For the delete operation to succeed the parent referenced object in the URI should be accessible. Depending on the operation one or more conditional delete SQL statements are issued into the database. The success or failure code returned from database is translated and propagated to user client as a result of the delete operation.
An example of deleting a network.

DELETE http://127.0.0.1:8888/building-A/networks/floor-1 

Configuring the Apache web server

Under the sliceable_routing_switch directory you will find a sub-directory Apache that includes a file with a name sliceable_routing_switch. It is an Apache configuration file. If you are familiar with Apache configuration feel free to change any settings to your customized needs. For example we use the HTTP port 8888 for the config.cgi program but that might be already reserved in your system by another web application. The DocumentRoot is a directory where the sliceable switch's web server scripts should be copied. Change this to whatever directory you wish or keep the default. At the moment make a note of this directory hereon refer as without the scripts path. After you completed all your changes use sudo privileges to copy this file to Apache sites-available directory.

sudo cp apache/sliceable_routing_switch /etc/apache2/sites-available

Note that you execute the above command from the apps/sliceable_routing_switch directory.
You need to execute the following commands to enable Apache modules and create symbolic links to your site configuration file.

sudo a2enmod rewrite actions  
sudo a2ensite sliceable_routing_switch  

Create the document root directory if you haven't already and use the following command to copy the scripts files.

sudo mkdir -p <document-root>/scripts  
sudo cp Slice.pm Filter.pm config.cgi <document-root>/scripts

Create a db directory below the directory and copy the database files.

sudo mkdir <document-root>/db  
sudo cp *.db <document-root>/db  

The config.cgi tries to access the database files, make sure that the perl global variables SliceDBFile and FilterDBFile point to the correct path. Propagate the right access and restart Apache and you are ready to go.

sudo chown -R www-data.www-data <document-root>
sudo /etc/init.d/apache2 reload  

To confirm that your configuration is free of errors use the curl tool or your installed browser to access the host at configured port for example http://127.0.0.1:8888/. You should see a 403 Forbidden message and the address of the Apache server.

Test Utility programs

Under the sliceable_routing_switch directory you will find two utility test programs slice and filter. Both programs provide a command line interface to database files slice and filter respectively. They allow you to save your data to a persistence store and to inspect to determine whether or not contains the data you expect.

Slice

At start up attempts to open the slice database file by reading the environment variable SLICE_DB_FILE if set or using a default name "slice.db". The program accepts an action verb that translates into a database operation to perform. Depending on the action verb a variable number of arguments must be supplied. Once all arguments parsed correctly a database operation is issued and the returned result is shown to the user. Invoking the program just by its name with no arguments displays a usage message on the screen.

./slice
Usage:
  slice list
  slice create SLICE_ID [DESCRIPTION]
  slice modify SLICE_ID DESCRIPTION
  slice destroy SLICE_ID
  slice add-port SLICE_ID DPID PORT VID [BINDING_ID]
  slice delete-port SLICE_ID BINDING_ID
  slice show-port SLICE_ID [BINDING_ID]
  slice add-mac SLICE_ID ADDRESS [BINDING_ID]
  slice delete-mac SLICE_ID BINDING_ID
  slice add-port-mac SLICE_ID PORT_BINDING_ID ADDRESS [BINDING_ID]
  slice delete-port-mac SLICE_ID PORT_BINDING_ID BINDING_ID
  slice show-port-mac SLICE_ID PORT_BINDING_ID [BINDING_ID]
  slice show-mac SLICE_ID [BINDING_ID]
  slice show SLICE_ID

The slice program accepts the following action verbs.

Create

Creates a new slice record given by its description. An example is shown below.

 ./slice create slice-1 north-tower

You can create a slice with a description containing spaces by quoting the description string. As expected initially the slice has no bindings as the show command indicates.

 ./slice show slice-1
[Description]
north-tower

No bindings found.

Attempting to add a slice that already exists should result in a failure message to be displayed and operation to be aborted.

Modify

Modifies the description of a slice record. The example below changes the description of a previous created slice from north to south.

./slice modify slice-1 south-tower

To confirm the outcome.

./slice show slice-1
[Description]
south-tower

No bindings found.

Destroy

Deletes a slice record. Any bindings attaches to the slice are also deleted. The command is not reversible.

./slice destroy slice-1
A slice is destroyed successfully.

List

Lists their IDs and description of all retrievable slice records.

./slice list
                              ID                     Description
                           net-1             research department
              132822846122249155          engineering department
                         slice-1                     south-tower

Add port

Adds a port binding to a slice. The following examples illustrates this operation:

./slice add-port slice-1 0xabc 1 1024 vswitch-1

In the above command the 0xabc is the datapath_id, 1 is the logical port number, and 1024 is the VLAN-ID assigned to a port and vswitch-1 is the binding id (name). Hereon the sliceable switch can receive and process packet-in events. To view the port binding use the show command.

./slice show slice-1
[Description]
south-tower

[Port-based bindings]
                      ID                 Datapath ID        Port             VID
               vswitch-1                       0xabc           1            1024

[MAC-based bindings]
No bindings found.

[MAC-based bindings on ports]
No bindings found

Delete port

Deletes a port binding from a slice. To delete the previous created port-binding issue the following command:

./slice delete-port slice-1 vswitch-1

"slice-1" is the slice ID and "vswitch-1" is the port binding id.

Show port

Lists all port bindings of a slice or a specific slice binding as shown below.

./slice show-port slice-1
[Port-based bindings]
                      ID                 Datapath ID        Port             VID
               vswitch-1                       0xabc           1            1024
               vswitch-2                       0xdef           2             512
./slice show-port slice-1 vswitch-1
[Port-based bindings]
                      ID                 Datapath ID        Port             VID
               vswitch-1                       0xabc           1            1024

Add MAC

Adds a MAC address binding to a slice. Since the slice ID is the primary key to this operation the same MAC address can be added to more than one slice. The following command adds a MAC address binding to a slice.

./slice add-mac slice-1 fe:01:da:c3:54:b3 mobile-host-1

To verify the result.

./slice show-mac slice-1
[MAC-based bindings]
                      ID                         MAC
           mobile-host-1           fe:01:da:c3:54:b3

Delete MAC

Deletes a MAC address binding from the slice.

Add port MAC

Adds a MAC address binding to a port binding presumably to indicate a mobile vswitch. The following example illustrates this.

./slice add-port-mac slice-1 vswitch-2 00:00:00:00:00:02 mobile-vswitch-2
./slice show-port-mac slice-1 vswitch-2
[MAC-based bindings on ports]
                      ID                 Datapath ID        Port             VID                         MAC
        mobile-vswitch-2                       0xdef           2             512           00:00:00:00:00:02

Delete port MAC

Deletes a port MAC address binding from a port binding. All port MAC bindings can be deleted as.

./slice delete-port-mac slice-1 vswitch-2

or to delete a specific port MAC binding.

./slice delete-port-mac slice-1 vswitch-2 mobile-vswitch-2

Filter

You use filter to filter out packets from unwanted sources. You can add, delete and list packet specifications. Data manipulated by the program is written in the filter database file. You can specify three actions with a packet filter specification, allow, deny, and local. By invoking the command name with no options displays a usage message on the screen with an explanation of each sub-command. Non-mandatory options are indicated in brackets. Omitting non-mandatory options for sub-commands like show and add causes no harm but for the delete sub-command the consequences are different all filter entries are deleted.

./filter
Usage:
  filter list
  filter show [FILTER_ID]
  filter add [FILTER_ID] [FILTER_CRITERIA]
  filter delete [FILTER_ID] [FILTER_CRITERIA]

The filter program accepts a number of sub-commands as explained below.

Add/show

The following example creates a filter that denies traffic to a specific destination MAC address on slice id net-1.

./filter add ethernet-switching dl_dst=00:00:00:00:00:01 slice=net-1 action=deny

The show command displays the results. You may omit the filter id in which case the show command displays all filter entries.

./filter show
[ethernet-switching]
            priority: 0
       ofp_wildcards: 0x3ffff7 (in_port,dl_src,dl_vlan,dl_vlan_pcp,dl_type,nw_tos,nw_proto,nw_src:32,nw_dst:32,tp_src,tp_dst)
             in_port: 0
              dl_src: 00:00:00:00:00:00
              dl_dst: 00:00:00:00:00:01
             dl_vlan: 0
         dl_vlan_pcp: 0
             dl_type: 0
              nw_tos: 0
            nw_proto: 0
              nw_src: 0.0.0.0/0
              nw_dst: 0.0.0.0/0
              tp_src: 0
              tp_dst: 0
           wildcards: 0x1 (in_datapath_id)
      in_datapath_id: 0
               slice: net-1
              action: DENY

The program creates an auto-generated id if you add a filter without specifying its filter id argument. The user can explicitly set the ofp_wildcards field as a number in decimal format. The ofp_wildcards field is a bitmask value for each field from in_port to tp_src fields inclusive. Clearing the bitmask value means that each specific condition is set and must be matched otherwise is set to don't care. An exact match flow would have the ofp_wildcards field to zero. The following example adds a filter to allow only traffic to a specific IP destination address on slice id net-1.

./filter add ip-routing nw_dst=10.10.10.1 slice=net-1 action=allow

The show command displays the results.

./filter show
[ip-routing]
            priority: 0
       ofp_wildcards: 0x303fff (in_port,dl_src,dl_dst,dl_vlan,dl_vlan_pcp,dl_type,nw_tos,nw_proto,nw_src:32,tp_src,tp_dst)
             in_port: 0
              dl_src: 00:00:00:00:00:00
              dl_dst: 00:00:00:00:00:00
             dl_vlan: 0
         dl_vlan_pcp: 0
             dl_type: 0
              nw_tos: 0
            nw_proto: 0
              nw_src: 0.0.0.0/0
              nw_dst: 10.10.10.1
              tp_src: 0
              tp_dst: 0
           wildcards: 0x1 (in_datapath_id)
      in_datapath_id: 0
               slice: net-1
              action: ALLOW

A more complicate example that denies traffic from port + ethernet + IP on slice net-1 datapath_id 0xabc is shown below.

./filter add port+ethernet+ip in_port=3 dl_src=00:00:00:00:00:02 dl_type=0x800 nw_dst=10.10.10.2 slice=net-1 in_datapath_id=0xabc action=allow

The result is:

./filter show port+ethernet+ip
[port+ethernet+ip]
            priority: 0
       ofp_wildcards: 0x303fea (dl_dst,dl_vlan,dl_vlan_pcp,nw_tos,nw_proto,nw_src:32,tp_src,tp_dst)
             in_port: 0x3
              dl_src: 00:00:00:00:00:02
              dl_dst: 00:00:00:00:00:00
             dl_vlan: 0
         dl_vlan_pcp: 0
             dl_type: 0x800
              nw_tos: 0
            nw_proto: 0
              nw_src: 0.0.0.0/0
              nw_dst: 10.10.10.2
              tp_src: 0
              tp_dst: 0
           wildcards: 0 (NONE)
      in_datapath_id: 0xabc
               slice: net-1
              action: ALLOW

Delete

To delete a specific filter entry.

./filter delete ethernet-switching

To delete all entries omit the filter name.

./filter delete

List

Use the list option to display the IDs of all registered filter entries.

./filter list
                      ID
              ip-routing
        port+ethernet+ip

Interaction with topology

Sliceable switch as a topology client at initiation indicates interest to receive events from topology by sending a subscription request. The topology acknowledges this by sending a response back to sliceable switch. Topology discovery running as a separate process discovers ports and links using the mechanisms of LLDP protocol and informs topology. Topology encapsulates such information as event objects and invokes the registered callbacks. The sliceable switch queries topology to receive a port status summary report. Topology based on discovery information packages datapath_id and port number for each port and notifies sliceable switch with the result. In turn sliceable switch will query topology to receive a summary of all discovered links. Topology groups from/to link information and reports the result back to sliceable switch. From now on sliceable switch is ready to receive asynchronous notifications from topology. The following sequence diagram depicts the exchange of messages between sliceable switch and topology.

sliceable-switch-topology

Hands on

Default mode

In this section we start a sliceable switch with the following configuration file and going through its operation step by step. You might also find the sliceable switch's cucumber features page useful in conjunction to this section. We need to start the sliceable switch application with root privileges since the program checks this and would abort otherwise. The root privileges required to redirect traffic to a local port if such filter entry is created. Make sure you use the -E option (to preserve user's environment variables) with sudo and start the application from Trema's top directory as shown below.

sudo -E ./trema run -c ../apps/sliceable_routing_switch/sliceable_routing_switch.conf

An excerpt of the configuration file loaded is shown below:

run {
  path "../apps/sliceable_routing_switch/sliceable_routing_switch"
  options "-s", "../apps/sliceable_routing_switch/slice.db", "-f", "../apps/sliceable_routing_switch/filter.db"
}

Sliceable switch accepts a number of command line arguments specified after the options keyword and separated by comma. One such option is sliceable switch's operational mode. The default mode is in affect since it is not supplied here. In this mode unknown or broadcast packets would be flooded to only those ports with the same slice number as the traffic received from the incoming port. Although we specified the slice and filter database files in this test their contents are empty. Our emulation network consists of four virtual hosts 1-4 a host attached to each virtual switch. Sending a packet from host1 to host2 should be dropped silently at sliceable switch as shown below:

./trema send_packets -s host1 -d host2
No slice found ( dpid = 0xe1, vid = 65535, match = [wildcards = 0, in_port = 2, dl_src = 00:00:00:00:00:01, dl_dst = 00:00:00:00:00:02, dl_vlan = 65535, dl_vlan_pcp = 0, dl_type = 0x800, nw_tos = 0, nw_proto = 17, nw_src = 192.168.0.1, nw_dst = 192.168.0.2, tp_src = 1, tp_dst = 1] ).

Let's use the slice utility program to register a slice and a port binding and see if we can go any further.

./slice create test_slice "debugging section"
./slice add-port test_slice 0xe1 2 65535 port-e1-2

From the debug output above we can infer that dpid=0xe1, in_port=2 and vid set to an undefined value (65535) and this is exactly what we set in the slice add-port command. Sending the packet again should pass this time but would it reach the destination? We observe that the "No slice found" debug is not shown anymore but did the packet delivered to host2. To confirm that we run the trema show_stats command on host2.

./trema show_stats host2  
Sent packets:

Received packets:

As can be seen the packet somehow did not find its way out. Enabling debug on sliceable switch will give us a hint.

export LOGGING_LEVEL=debug  
sudo -E ./trema run -c ../apps/sliceable_routing_switch/sliceable_routing_switch.conf

Sending a packet again to host2 and looking through the debug output we find out that following message.

Looking up filter entry ( wildcards = 0, in_datapath_id = 0xe1, slice_number = 0x1, ofp_match = [wildcards = 0, in_port = 2, dl_src = 00:00:00:00:00:01, dl_dst = 00:00:00:00:00:02, dl_vlan = 65535, dl_vlan_pcp = 0, dl_type = 0x800, nw_tos = 0, nw_proto = 17, nw_src = 192.168.0.1, nw_dst = 192.168.0.2, tp_src = 1, tp_dst = 1] ).
Filter entry not found.
Filter: DENY ( dpid = 0xe1, slice = 0x1, match = [wildcards = 0, in_port = 2, dl_src = 00:00:00:00:00:01, dl_dst = 00:00:00:00:00:02, dl_vlan = 65535, dl_vlan_pcp = 0, dl_type = 0x800, nw_tos = 0, nw_proto = 17, nw_src = 192.168.0.1, nw_dst = 192.168.0.2, tp_src = 1, tp_dst = 1] ).

The statement that matters the most is the Filter: DENY. We have two choices either create a specialized filter entry for this flow only or create a more general entry to cover a range of flows. At the moment we choose the most general case and create a filter entry that will allow every packet from dpid 0xe1 to belong to test-slice.

./filter add "all-traffic-from-0xe1" slice=test-slice in_datapath_id=0xe1 action=allow

Sending the packet again we observe that a filter entry match is found.

Looking up filter entry ( wildcards = 0, in_datapath_id = 0xe1, slice_number = 0x1, ofp_match = [wildcards = 0, in_port = 2, dl_src = 00:00:00:00:00:01, dl_dst = 00:00:00:00:00:02, dl_vlan = 65535, dl_vlan_pcp = 0, dl_type = 0x800, nw_tos = 0, nw_proto = 17, nw_src = 192.168.0.1, nw_dst = 192.168.0.2, tp_src = 1, tp_dst = 1] ).
A filter entry found (list).
Filter: ALLOW ( dpid = 0xe1, slice = 0x1, match = [wildcards = 0, in_port = 2, dl_src = 00:00:00:00:00:01, dl_dst = 00:00:00:00:00:02, dl_vlan = 65535, dl_vlan_pcp = 0, dl_type = 0x800, nw_tos = 0, nw_proto = 17, nw_src = 192.168.0.1, nw_dst = 192.168.0.2, tp_src = 1, tp_dst = 1] ).

The next step is for the sliceable switch to look up the forwarding db to locate the outgoing dpid and port. Since no entries exist yet the packet is to be flooded on the network. But unless a port-based binding or a mac-based binding exists for the destination host the packet is discarded. The easiest way is to create a port-based binding using the slice add-port command.

./slice add-port test-slice 0xe2 1 0xffff port-e2-1

Finally you can verify that packets can flow in either direction between the two hosts 1 and 2 by using the send_packets and show_stats commands. The above procedure would also work if instead of port-based bindings you use mac-based bindings.

Default mode (mac-based bindings)

We start off the test by registering two slices and configure a single virtual switch with 4 virtual hosts attached. We start sliceable switch in default mode as follows:

run {
  path "../apps/sliceable_routing_switch/sliceable_routing_switch"
  options "-s", "../apps/sliceable_routing_switch/slice.db", "-f", "../apps/sliceable_routing_switch/filter.db"
}

Our slices configured to have only mac-based bindings for 3 virtual hosts. The actual configuration for both slices is shown below:

[Description]
slice1

[Port-based bindings]
No bindings found.

[MAC-based bindings]
                      ID                         MAC
                   host2           00:00:00:00:00:02
                   host1           00:00:00:00:00:01

[MAC-based bindings on ports]
No bindings found.

[Description]
slice2

[Port-based bindings]
No bindings found.

[MAC-based bindings]
                      ID                         MAC
                   host3           00:00:00:00:00:03

[MAC-based bindings on ports]
No bindings found.

We left host4 unregistered to simulate the case of unknown packets. The following summarizes the results of our test conducted with packets traversing between hosts. Host names are abbreviated for clarity reasons.

test packet host1 host2 host3 host4 comment
h1->h2 X Host2 did not receive the first packet because the flooding process is disabled even if destination host2 found to be on the same slice as host1.
h2->h1 This time host1's MAC address is known and a flow mod is installed to deliver the packet to host1.
h1->h2 Host1 and host2 can exchange packets as normal.
h1->h3 X Same case as before (host1 transmitting to host2).
h3->h1 X Since host3 and host1 belong to different slices sliceable switch prohibits traffic between them.
h1->h3 X Traffic is stopped because host1 and host3 belong to different slices.
h1->h4 X Although action is to flood since host4 is unknown destination but since in this mode flooding is restricted no packets seen out of sliceable switch.
h4->h1 X Unknown host4 is treated as belonging to undefined slice.
h1->h4 X Even if MAC learning (forwarding db) returns true no slice is found for host4 therefore the packet is discarded.

Loose mode (mac-based bindings)

Prerequisites for this test necessitates a network of a single virtual switch with 4 virtual hosts. We create two slices and register mac-binding for the first 3 virtual hosts. Loose mode operational mode is set with the -m option as shown below:

run {
  path "../apps/sliceable_routing_switch/sliceable_routing_switch"
  options "-m", "-s", "../apps/sliceable_routing_switch/slice.db", "-f", "../apps/sliceable_routing_switch/filter.db"
}

In addition our slice and filter configuration after setup is as follows:

[Description]
slice1

[MAC-based bindings]
                      ID                         MAC
                   host2           00:00:00:00:00:02
                   host1           00:00:00:00:00:01

[Description]
slice2

[MAC-based bindings]
                      ID                         MAC
                   host3           00:00:00:00:00:03

[default]
            priority: 0
       ofp_wildcards: 0x3fffff (in_port,dl_src,dl_dst,dl_vlan,dl_vlan_pcp,dl_type,nw_tos,nw_proto,nw_src:32,nw_dst:32,tp_src,tp_dst)
             in_port: 0
              dl_src: 00:00:00:00:00:00
              dl_dst: 00:00:00:00:00:00
             dl_vlan: 0
         dl_vlan_pcp: 0
             dl_type: 0
              nw_tos: 0
            nw_proto: 0
              nw_src: 0.0.0.0/0
              nw_dst: 0.0.0.0/0
              tp_src: 0
              tp_dst: 0
           wildcards: 0x3 (in_datapath_id,slice)
      in_datapath_id: 0
               slice: UNDEFINED (0)
              action: ALLOW

Sending a packet from host1 to host2 we expect and confirm that the packet reaches host2. In similar fashion we confirm that we are capable of transmitting and receiving packets from host1 to host3. Finally we confirm that in this mode is also possible to send and receive a single packet for example from host1 to host4. Host4 receives the packet as a result of the flooding process since the destination MAC address is unknown. Going in the opposite direction (host4->host1) is not possible since host4 is not associated with any slice. The complete test process is diagrammatically shown below, for clarity the color is the same for hosts attached to the same slice.

loose-mode1

The table below summarizes all our test results:

test packet host1 host2 host3 host4
host1->host2
host2->host1
host1->host2
host1->host3
host3->host1 X
host1->host3 X
host1->host4
host4->host1 X
host1->host4 X

This completes our test but there are many cases to be tested like increasing the number of virtual switches or slices but the end result is the same loose mode allows first packets to be flooded and received by hosts.

Loose (inter-slice - broadcast packet)

In this example we set the operational mode to loose (-m) and examine the behavior of sliceable switch's when it receives a broadcast packet. A forwarding db search would always return false for a broadcast packet therefore the default action is to flood the packet on the network. This is done as follows:

  • From the transmitted packet to a configured ingress port sliceable switch determines the slice number.
  • Using the determined slice number it cycles through each vswitch and outputs a packet-out to each port that a virtual host is attached unless a pre-condition is met. This pre-condition is that any mac-based binding must exist for the ingress found slice.
    Note: This description somehow deviates from the theory that states that a packet-out would be sent to every port independently of what the slice number is. The following diagram depicts the test configuration and shows the sequences of messages when a broadcast packet is transmitted to an ingress port of vswitch (0xe1):

broadcast-loose-1 From the above diagram we observe that a packet-out is only transmitted to vswitch(0xe2) that belongs to the same slice as vswitch(0xe1).
If we register a MAC-based binding for example for host1 and repeat the test we observe that a packet-out is transmitted to every vswitch. The diagram below illustrates this:

broadcast-loose-2

Restrict mode (MAC-based bindings on ports)

This is kind of unique operational mode where registered MAC-based bindings on ports become effective in determining the slice number. Our test configuration includes two slices, one virtual switch and three registered hosts and an unknown host. The slice configuration includes the following entries:

[Description]
slice1

[Port-based bindings]
                      ID                 Datapath ID        Port             VID
                   host2                         0x1           1           65535
                   host1                         0x1           3           65535

[MAC-based bindings]
No bindings found.

[MAC-based bindings on ports]
                      ID                 Datapath ID        Port             VID                         MAC
               host2_mac                         0x1           1           65535           00:00:00:00:00:02
               host1_mac                         0x1           3           65535           00:00:00:00:00:01
[Description]
slice2

[Port-based bindings]
                      ID                 Datapath ID        Port             VID
                   host3                         0x1           2           65535

[MAC-based bindings]
No bindings found.

[MAC-based bindings on ports]
                      ID                 Datapath ID        Port             VID                         MAC
               host3_mac                         0x1           2           65535           00:00:00:00:00:03

Exchanging of packets between hosts belonging to the same slice (host1, host2 or vice-versa) is possible but for not for unknown hosts or hosts belonging to different slices. The following table summarizes the test results.

test packet host1 host2 host3 host4 comment
h1->h2 Vswitch forwards the packet-out destined for host2 sent by sliceable switch.
h2->h1 Sliceable switch installs a flow to output packet to host1 followed by a packet-out to host1.
h1->h2 Sliceable switch installs a flow to output packet to host2 followed by a packet-out to host2.
h1->h3 X Although a packet-out is sent with action set to output to host1, vswitch drops the packet because it is addressed to host3.
h3->h1 X Source and destination on different slices. Sliceable switch installs an expire flow to reject any packets destined to host1.
h1->h3 X This time sliceable switch installs a flow to reject any packets destined for host3.
h1->h4 X Sliceable switch sends a packet-out with action set to output the packet to host2 but dropped since not addressed for it.
h4->h1 X Since no slice found for host4 sliceable switch responds by severing the source host4.
h1->h4 X Again no slice found for unknown host4, a flow is installed to refrain sending packets to host4 from host1.

Using the restrict operational mode sliceable switch provides a security layer for a use-case where in a mobile access network intruding users attempt to access the network using fake MAC addresses. Of-course sliceable switch can not stop malicious users to probe for other hosts by guessing target addresses and using them in packet-ins.

Redirector

In this section we will explain the steps taken when a filter action set to local. That is to redirect the incoming packet-in to a pre-configured tun network interface. From user's point of view a tun network interface behaves similar to any other Ethernet network interface. However we don't send the packet into a wire but we inject that packet into kernel's IP stack for the iptables tool to read. Unless packet-in user's payload is an IPv4 packet redirection would abort otherwise source information (source MAC address, source IPv4 address, datapath_id and ingress port) added in the host db table. Then the packet is sent to the tun network interface without the layer 2 header. With the help of iptables tool traffic is read from tun network interface and destination address translation takes place. The destination address can be either a virtual or a real physical address. In this example we use a virtual address that we set prior to executing this test.

sudo ifconfig eth0:1 192.168.1.200 netmask 255.255.255.0 up

The iptables command to invoke to do the address translation is the following:

/sbin/iptables -t nat -A PREROUTING -i of0 -j DNAT -p udp --to-destination 192.168.1.200

As soon as the packet is read from the tun network interface the destination IPv4 address is checked to verify that this is actual our packet and to retrieve other destination information. Finally we construct a layer 2 header using a static source MAC address (00:00:00:01:01:01) and destination MAC address set to the received source MAC address to send a packet-out to source.

Packet-out actions

A port known to sliceable switch has certain characteristics. A port which a virtual host is attached to is an external port. A port that interconnects one vswitch with another is named as such and referred to by this name. The first check before sending a packet-out is to ensure that the port to packet-out is an external port in other words there is a virtual host attached to it. A check also ensures that a packet-out is not sent to originating source. Constructing packet-out actions proceeds by translating VLAN-IDs if required or setting the packet-out output port. At this stage the output slice and port number already known and used to obtain the output VLAN-ID. This is only feasible if a port-based binding entry exists. The search returns a VLAN-ID or a dummy no VLAN-ID value. For a valid VLAN-ID within the 4K range, set its value in packet-out's action list otherwise for an invalid set an action to remove its value. If unable to find an output VLAN-ID and sliceable's switch operational mode is default or restrict, processing is abruptly terminated. Otherwise continue and check if for the output slice any mac-based bindings entries exist. If this test passes an action to output to port number is formed and we are ready to send the packet-out.

Reducing packet-outs

This section introduces an example to illustrate the concept of network traffic reduction. The benefits are quite evident in a network where traffic is exchanged between two edge nodes with lots of intermediates in between. First we will show the case (see diagram below) where packet-outs are broadcasted.

more packet-outs

This is case where there is a port-based binding entry for each vswitch. If we send a packet from host1 to host4 since destination host4 is unknown a packet-out is flooded for each registered port-based binding entry. From the diagram we can infer that packet-outs to vswitch#2 and vswitch#3 even if omitted have no affect on the destination packet at host4. Sending a packet in the opposite direction from host4 to host1 a packet-out is sent to vswitch#1 (see diagram below) and hereon any additional packets would flow smoothly between both hosts on the data plane.

packet from host4-host1

Next we delete the port-based binding entries from vswitch#2 and vswitch#3 since these vswitches only repeat traffic (see diagram below).

less packet-outs

We start by sending a packet from host1 to host4 and observe that only a single packet-out is sent out to vswitch#4. To conclude the test we send a packet from host4 to host1 (see diagram below).

packet from host4-host1

The last step is identical to the previous described and necessary to set up the data plane correctly.

Inter-slice filtering

This section demonstrates an easy way to separate traffic even within a vswitch by declaring a distinct slice number to each experimental host. Effectively it creates an invisible barrier stopping traffic entering a host not belonging to the same slice as the sender. Although an example the same principal can be applied to an enterprise network to separate different kinds of traffic like video and data. The configuration file for this example is the same as in the previous examples with the following slice configuration (see also diagram):

inter-slice1

./slice show test-slice
[Description]
debugging section

[Port-based bindings]
                      ID	         Datapath ID	    Port	     VID
               port-e1-2	                0xe1	       2	   65535

[MAC-based bindings]
No bindings found.

[MAC-based bindings on ports]
No bindings found.  

./slice show video-slice
[Description]
video test slice

[Port-based bindings]
                      ID	         Datapath ID	    Port	     VID
               port-e4-2	                0xe4	       2	   65535

[MAC-based bindings]
No bindings found.

[MAC-based bindings on ports]
No bindings found.

Based on the above configuration we assign two slices one for host1 (test-slice) and another for host4 (video-slice) and create a port-based binding for each. Sending a packet form host1 we can easily predict that the packet should not find its way to host4. We confirm this by the show_stats command:

./trema show_stats host4
Sent packets:
Received packets:

No counter figures shown for host4. Sending a packet from host4 to host1 we can confirm that host1 didn't receive any packets at all (see diagram below)

inter-slice2

./trema show_stats host1
Sent packets:
ip_dst,tp_dst,ip_src,tp_src,n_pkts,n_octets
192.168.0.4,1,192.168.0.1,1,1,50
Received packets:

The debug output also verifies the same result as can be seen below:

Lookup mac:00:00:00:00:00:01
Found at dpid = 0xe1, port = 2
No slice found.
Destination is on different slice ( slice = 0x2, out_slice = 0xffff ).

Host1's MAC address is looked up in forwarding db and found to belong to datapath_id 0xe1 and outgoing port 2. Using the sender's slice number which is video-slice(2) perform a search to locate the outgoing VLAN-ID. Of-course a match is not to be found and as a result of this the destination MAC address is used to perform a search in MAC-based bindings to locate the outgoing slice. Since a MAC-based bindings doesn't exist a "No slice found" message is displayed and the slice number set to an invalid value 0xffff. To prevent packet-ins clogging the network sliceable switch installs a flow to match and drop those packets at source.