Under Construction

This site is under construction. The tutorial and documentation are not yet complete, and the VM has not been extensively tested.

This tutorial explains how to run three example applications on CoVisor. These examples illustrate parallel composition, sequential composition, and topology virtualization. They are adapted from the examples in Figures 5 and 6 of the paper. This tutorial covers ctrl.py, a Python script located in /home/covisor/CoVisor/experiments. ctrl.py is a wrapper around various calls to the CoVisor API, but this tutorial does not (yet) go into detail about the API.

Setup

To run ctrl.py, log into the CoVisor VM and switch into the CoVisor/experiments directory.

covisor cd CoVisor/experiments
In all of the following examples, after you type the initial command you should see messages about killing Mininet, Floodlight, and OVX and then messages about starting Floodlight. Do not worry if you see Unable to contact the remote controller at 127.0.0.1:6633; the controller has not yet been booted. After 20 seconds, you should see messages indicating that virtual switches have been created and connected to a controller.

If, instead, you see output like this
try increasing the constant SLEEP_TIME defined at the top of ctrl.py.

Topology

The figure below shows the topology for all three examples. Parallel and sequential composition use just the physical topology in the lower half of the figure; the virtualization example abstracts the single physical switch to the three node network in the upper half of the figure.

Parallel Composition

We start with the parallel composition of a monitoring application $M$ with a routing application $Q$. $M$ counts (and then drops) all packets with $srcip=1.0.0.0/24$ and immediately drops all other packets. $Q$ forwards packets with $dstip=2.0.0.1$ out port 1, packets with $dstip=2.0.0.2$ out port 2, and drops all other packets. The parallel composition $M + Q$ counts and forwards out port 1 all packets with both $srcip=1.0.0.0/24$ and $dstip=2.0.0.1$, counts and forwards out port 2 all packets with both $srcip=1.0.0.0/24$ and $dstip=2.0.0.2$, counts and drops all other packets with $srcip=1.0.0.0/24$, and immediately drops all other packets.

Flow Table for $M$
$(1; srcip=1.0.0.0/24; count)$
$(0; *; drop)$
Flow Table for $Q$
$(1; dstip=2.0.0.1; fwd(1))$
$(1; dstip=2.0.0.2; fwd(2))$
$(0; *; drop)$
Composed Flow Table $M + Q$
$(2; srcip=1.0.0.0/24,dstip=2.0.0.1; fwd(1), count)$
$(2; srcip=1.0.0.0/24,dstip=2.0.0.2; fwd(2), count)$
$(1; srcip=1.0.0.0/24; count)$
$(1; dstip=2.0.0.1; fwd(1))$
$(1; dstip=2.0.0.2; fwd(2))$
$(0; *; drop)$

To run this example, type the following command.

covisor sudo python ctrl.py expr-parallel

sudo is necessary because ctrl.py starts Mininet, and Mininet must run as root.

sudo python ctrl.py expr-parallel starts the Mininet command line interface (CLI). See mininet.org for information and documentation. You can verify that the physical switch's flow table matches the above Composed Flow Table $M + Q$ by typing

mininet> dpctl dump-flows
To type exit to exit the Mininet CLI.
mininet> exit

Sequential Composition

Now, we sequentially compose a simple load balancer $L$ with a the same routing application from above ($Q$). $L$ rewrites the destination IP address of all packets destined to $3.0.0.0$ matching $scrip=0.0.0.0/2$ to $2.0.0.1$. For all remaining packets destined to $3.0.0.0$, the $L$ rewrites the destination IP to $2.0.0.2$. $L$ drops all other packets. Then, $Q$ forwards all packets not dropped by $L$ and matching $dstip=2.0.0.1$ out port 1 and all packets not dropped by $L$ and with $dstip=2.0.0.2$ out port 2. Any other packets are dropped.

Flow Table for $L$
$(3; srcip=0.0.0.0/2, dstip=3.0.0.0; \\ \hspace{10pt} dstip=2.0.0.1)$
$(1; dstip=3.0.0.0; dstip=2.0.0.2)$
$(0; *; drop)$
Flow Table for $Q$
$(1; dstip=2.0.0.1; fwd(1))$
$(1; dstip=2.0.0.2; fwd(2))$
$(0; *; drop)$
Composed Flow Table $L \gg Q$
$(25; srcip=0.0.0.0/2, dstip=3.0.0.0;\\ \hspace{10pt} dstip=2.0.0.1, fwd(1))$
$(9; dstip=3.0.0.0; dstip=2.0.0.2, fwd(2))$
$(0; *; drop)$

To run this example, type the following command.

covisor sudo python ctrl.py expr-sequential

Again, you can see the composed flow table by running dpctl dump-flows from the Mininet command line. You'll see the flow table has the additional rules $r_{24} = (24; srcip=0.0.0.0/2, dstip=3.0.0.0; dstip=2.0.0.1)$ and $r_8 = (8; dstip=3.0.0.0; dstip=2.0.0.2)$ not shown in the table above. But, these flow tables are functionally equivalent, because all packets matching $r_{24}$ will be processed by the rule with priority 25, and all packets matching $r_8$ will be processed by the rule with priority 9.

Topology Virtualization

def virtCreatePlumbingGraph():
    cmd = "%s -n createPlumbingSwitch 00:00:00:00:00:00:01:00 3" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingPort 00:00:00:00:00:00:01:00 0 1" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingPort 00:00:00:00:00:00:01:00 0 2" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingPort 00:00:00:00:00:00:01:00 0 0" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingPort 00:00:00:00:00:00:01:00 1 0" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingPort 00:00:00:00:00:00:01:00 1 3" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingPort 00:00:00:00:00:00:01:00 1 0" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingPort 00:00:00:00:00:00:01:00 2 0" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingPort 00:00:00:00:00:00:01:00 2 4" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingPort 00:00:00:00:00:00:01:00 2 5" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingLink 00:00:00:00:00:00:01:00 0 3 1 1" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPlumbingLink 00:00:00:00:00:00:01:00 1 3 2 1" % ovxctlPy
    subprocess.call(cmd, shell=True)

def virtAddController1(topo):
    print "*****************************"
    print "******** Controller 1 *******"
    print "*****************************"
    cmd = "%s -n createNetwork tcp:%s:10000 10.0.0.0 16" % (ovxctlPy,
        CONTROLLER_IP)
    subprocess.call(cmd, shell=True)

    cmd = "%s -n createSwitch 1 00:00:00:00:00:00:01:00 0" % ovxctlPy
    subprocess.call(cmd, shell=True)

    cmd = "%s -n startNetwork 1" % ovxctlPy
    subprocess.call(cmd, shell=True)

def virtAddController2(topo):
    print "*****************************"
    print "******** Controller 2 *******"
    print "*****************************"
    cmd = "%s -n createNetwork tcp:%s:20000 10.0.0.0 16" % (ovxctlPy,
        CONTROLLER_IP)
    subprocess.call(cmd, shell=True)

    cmd = "%s -n createSwitch 2 00:00:00:00:00:00:01:00 1" % ovxctlPy
    subprocess.call(cmd, shell=True)

    cmd = "%s -n startNetwork 2" % ovxctlPy
    subprocess.call(cmd, shell=True)

def virtAddController3(topo):
    print "*****************************"
    print "******** Controller 3 *******"
    print "*****************************"
    cmd = "%s -n createNetwork tcp:%s:30000 10.0.0.0 16" % (ovxctlPy,
        CONTROLLER_IP)
    subprocess.call(cmd, shell=True)

    cmd = "%s -n createSwitch 3 00:00:00:00:00:00:01:00 2" % ovxctlPy
    subprocess.call(cmd, shell=True)

    cmd = "%s -n startNetwork 3" % ovxctlPy
    subprocess.call(cmd, shell=True)

def virtCreatePolicy():
    cmd = "%s -n createPolicy 00:00:00:00:00:00:01:00 0 1" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPolicy 00:00:00:00:00:00:01:00 1 2" % ovxctlPy
    subprocess.call(cmd, shell=True)
    cmd = "%s -n createPolicy 00:00:00:00:00:00:01:00 2 3" % ovxctlPy
    subprocess.call(cmd, shell=True)

def exprVirt():
    cleanAll()
    startFloodlight(3)
    startOVX()
    (topo, net) = startMininet()
    time.sleep(5)
    virtCreatePlumbingGraph()
    virtAddController1(topo)
    virtAddController2(topo)
    virtAddController3(topo)
    createACL('1 dltype:exact,dstip:prefix output')
    createACL('2 dltype:exact,dstip:prefix output,mod:dstip')
    createACL('3 dltype:exact,dstip:prefix output')
    virtCreatePolicy()
    app = DemoVirtApp(topo)
    app.installRules()
    CLI(net)