Ravel Overview

Ravel allows multiple applications to execute simultaneously and collectively drive network control. This is accomplished through orchestration. A Ravel user sets priorities on the orchestrated applications using the ordering passed to the orch load command. (For more details, see the orchestration demo in the Walkthrough.)

Applications can propose updates (through an insertion, deletion, or update to one of its views), which are then checked against the policies of all other orchestrated applications. If the proposed update violates the constraints of another application, a higher priority application can overwrite the update.

Ravel Base Tables

Ravel uses a flat representation of the network and exposes the topology and forwarding tables as SQL tables. Tables that may be of interest to applications are:

/* Topology table - pairs of connected nodes
 * sid: switch id
 * nid: next-hop id
 * ishost: if nid is a host
 * isactive: if the sid-nid link is online
 * bw: link bandwidth
 */
tp(sid integer, nid integer, ishost integer, isactive integer, bw integer)

/* Configuration table - per-switch flow configuration
 * fid: flow id
 * pid: id of previous-hop node
 * sid: switch id
 * nid: id of next-hop node
 */
cf (fid integer, pid integer, sid integer, nid integer)

/* Reachability matrix - end-to-end reachability
 * fid: flow id
 * src: the IP address of the source node
 * dst: the IP address of the destination node
 * vol: volume allocated for the flow
 * FW: if flow should pass through a firewall
 * LB: if flow should be load balanced
 */
tm (fid integer, src integer, dst integer, vol integer, FW integer, LB integer)

Additional node tables include:

/* Host table
 * hid: host id
 * ip: host's IP address
 * mac: host's MAC address
 * name: hostname (in Mininet)
 */
hosts (hid integer, ip varchar, mac varchar, name varchar)

/* Switch table
 * sid: switch id (primary key, NOT datapath id)
 * dpid: datapath id
 * ip: switch's IP address
 * mac: switch's MAC address
 * name: switch's name (in Mininet) 
 */
switches (sid integer, dpid varchar, ip varchar, mac varchar, name varchar)

/* Node view - all nodes and switches in the network
 * id: the node's id from its respective table (hosts.hid or switches.sid)
 * name: the node's name
 */
nodes (id integer, name varchar)

Developing Applications

Applications in Ravel can consist of two components: an implementation in SQL and a sub-shell implemented in Python. Application sub-shells provide commands to monitor and control the application from the Ravel CLI. Name the SQL file [appname].sql and the Python file [appname].py, and place both files in the apps/ directory. The CLI will search for SQL and Python files in this directory.

For an overview of the CLI and application superclasses, see the API.

SQL Component

An application’s SQL component can create tables, views on Ravel base tables, or add triggers on Ravel base tables. To interact with orchestration, an application must define its constraints and a protocol for reconciling conflicts. To add constraints, create a violation table in the form appname_violation. To create a repair protocol, add a rule in the form appname_repair.

For example, suppose we want to implement a bandwidth monitor that limits flows to a particular rate (see apps/merlin.sql for the full implementation). We can create a table to store the rate for each flow:

CREATE TABLE bw_policy (
    fid      integer,
    rate     integer,
    PRIMARY KEY(fid)
);

And then a violation table that finds flows that violate the constraint fid < rate:

CREATE VIEW bw_violation AS (
    SELECT tm.fid, rate AS req, vol AS asgn
	FROM tm, bw_policy
	WHERE tm.fid = bw_policy.fid AND rate > vol
);

If the view contains more than zero rows, a conflict has occurred. To repair a conflict, we can reset the flow rate:

CREATE RULE bw_repair AS
    ON DELETE TO bw_violation
    DO INSTEAD
        UPDATE tm SET vol=OLD.req WHERE fid=OLD.fid;

Python Sub-Shell

To interact with an application, the Ravel CLI can load a shell with commands for monitoring and controlling the application’s behavior. An application sub-shell can be launched from the Ravel CLI by typing the application’s name or shortcut after it has been loaded. To create a sub-shell, create a Python file with a class extending AppConsole and add the following variables:

  • shortcut: defines a shortcut for the application from the Ravel CLI
  • description: a short description of the application
  • console: defines the class inheriting AppConsole

For example:

from ravel.app import AppConsole

class MyConsole(AppConsole):
    do_echo(self, line):
        "Echo input"
        print "MyConsole says:", line

shortcut = "my"
description = "my demo console"
console = MyConsole

The AppConsole class contains the properties:

For more information about the application superclasses and their properties, see the API.

Measuring Performance

The Ravel CLI provides the command time to measure the execution time of a command, similar to the Linux time command: time [command] [command args].

For more granular inspection of performance, the Ravel CLI provides a profile command. This command reports the execution time of manually-defined blocks of code. When extending the Ravel runtime or developing applications, a new block of code can be defined using the class profiling.PerfCounter. The constructor accepts a string to identify the block of code. The functions start() and stop() define the start and end of the code to be profile:

from ravel.profiling import PerfCounter

def my_profiled_function():
    pc = PerfCounter("name of code block")
    pc.start()

    # will measure the execution time of the code here

    pc.stop()