Skip to content

Controlling NetASM Switch using POX

Muhammad Shahbaz edited this page Jun 21, 2015 · 6 revisions

In previous examples, we used CLI or Mininet python API for specifying policies and installing flow rules in the NetASM switch. This time we will see how to do this using a POX controller. To enable POX to communicate with our switch, we have used the OpenFlow vendor extensions. The supported APIs are listed in the api.py file.

Here's an example of a simple table-based pass-through application written in POX, code.

from pox.core import core
from pox.lib.util import dpidToStr

from netasm.netasm.core.common import ports_to_bitmap
from netasm.back_ends.soft_switch.api import OutMessage, InMessage, QueryMessage


log = core.getLogger()


def _handle_VendorIn(event):
    in_msg = InMessage(event.ofp)

    if in_msg.is_query_table_entry:
        print "Query Table Entry: %s %s %s" % (in_msg.table_name, in_msg.table_index, in_msg.table_entry)
    elif in_msg.is_query_table_list:
        print "Query Table List: %s" % (in_msg.table_list, )


def _handle_ConnectionUp(event):
    msg = OutMessage()

    msg.set_policy("netasm.examples.netasm.controller_assisted.table_based_simple")
    event.connection.send(msg)

    msg.add_table_entry('match_table', 0,
                        {'eth_src': (0x000000000001, 0xFFFFFFFFFFFF)})
    event.connection.send(msg)
    msg.add_table_entry('params_table', 0,
                        {'outport_bitmap': ports_to_bitmap(2)})
    event.connection.send(msg)

    msg.add_table_entry('match_table', 1,
                        {'eth_src': (0x000000000002, 0xFFFFFFFFFFFF)})
    event.connection.send(msg)
    msg.add_table_entry('params_table', 1,
                        {'outport_bitmap': ports_to_bitmap(1)})
    event.connection.send(msg)

    msg = QueryMessage()

    msg.table_entry('match_table', 0)
    event.connection.send(msg)
    msg.table_entry('params_table', 0)
    event.connection.send(msg)

    msg.table_entry('match_table', 1)
    event.connection.send(msg)
    msg.table_entry('params_table', 1)
    event.connection.send(msg)

    msg.table_list()
    event.connection.send(msg)

    log.info("netasm.examples.netasm.controller_assisted.table_based_simple (pass through) for %s",
             dpidToStr(event.dpid))


def launch():
    core.openflow.addListenerByName("ConnectionUp", _handle_ConnectionUp)
    core.openflow.addListenerByName("VendorIn", _handle_VendorIn)

    log.info("netasm.examples.netasm.controller_assisted.table_based_simple (pass through) running.")

In the _handle_ConnectionUp function, we first specify the policy that we want the NetASM switch to implement. To do this, we create an OutMessage() object and then use its set_policy() function to specify the policy (for this example, we are using the table_based_simple policy). We then send the message to the switch using the event.connection.send() function.

    msg = OutMessage()

    msg.set_policy("netasm.examples.netasm.controller_assisted.table_based_simple")
    event.connection.send(msg)

Once the policy is installed, we then populate the tables using the add_table_entry() function. To find out the names of the tables, we can consult the NetASM policy.

    msg.add_table_entry('match_table', 0,
                        {'eth_src': (0x000000000001, 0xFFFFFFFFFFFF)})
    event.connection.send(msg)
    msg.add_table_entry('params_table', 0,
                        {'outport_bitmap': ports_to_bitmap(2)})
    event.connection.send(msg)

After the tables have been populated, for sanity check, we query the tables to read back the installed rules. For this, we create a QueryMessage() object and use its table_entry() function to query the table.

    msg.table_entry('match_table', 0)
    event.connection.send(msg)
    msg.table_entry('params_table', 0)
    event.connection.send(msg)

The results of the query are received back as a VendorIn event. We have registered the _handle_VendorIn() function for processing these events. Inside this function, we create an InMessage() object using the event.ofp argument. We then check if the message is a query message (e.g., is_query_table_entry), if so, we print the results.

    in_msg = InMessage(event.ofp)

    if in_msg.is_query_table_entry:
        print "Query Table Entry: %s %s %s" % (in_msg.table_name, in_msg.table_index, in_msg.table_entry)

Testing with Mininet

We will now test our POX controller application using Mininet. We will create a single switch topology using the NetASM switch. To do so, we run the following command.

$ sudopy ~/netasm/netasm/examples/back_ends/soft_switch/mininet/single_switch.py --cli --ports=2

We should see the following output.

*** Creating network
*** Adding controller
Unable to contact the remote controller at 127.0.0.1:6633
*** Adding hosts:
h1 h2 
*** Adding switches:
s1 
*** Adding links:
(h1, s1) (h2, s1) 
*** Configuring hosts
h1 h2 
*** Run this command in a separate terminal then press Enter!
sudopy python /home/vagrant/pox/pox.py --no-openflow netasm.back_ends.soft_switch.datapath --address=127.0.0.1 --port=6633 --dpid=0000000000000001 --policy= --ports=s1-eth1,s1-eth2 --ctl_port=7791

Mininet is waiting for us to run the above command in a new terminal and then press Enter.

In a new terminal, run this command. This will start the NetASM datapath.

$ sudopy python /home/vagrant/pox/pox.py --no-openflow netasm.back_ends.soft_switch.datapath --address=127.0.0.1 --port=6633 --dpid=0000000000000001 --policy= --ports=s1-eth1,s1-eth2 --ctl_port=7791

NetASM datapath is now waiting for a controller to connect with.

Go back to the Mininet terminal and press Enter.

We will now run the POX controller with our application. Open up a new terminal and run the following command.

$ sudopy ./pox/pox.py netasm.examples.controllers.pox.table_based_pass_through

Upon connection with the NetASM switch, we should see the following output.

POX 0.2.0 (carp) / Copyright 2011-2013 James McCauley, et al.
INFO:.home.vagrant.netasm.netasm.examples.controllers.pox.table_based_pass_through:netasm.examples.netasm.controller_assisted.table_based_simple (pass through) running.
INFO:core:POX 0.2.0 (carp) is up.
INFO:openflow.of_01:[00-00-00-00-00-01 1] connected
INFO:.home.vagrant.netasm.netasm.examples.controllers.pox.table_based_pass_through:netasm.examples.netasm.controller_assisted.table_based_simple (pass through) for 00-00-00-00-00-01
Query Table Entry: match_table 0 {'eth_src': {'mask': 281474976710655, 'value': (1, 48)}}
Query Table Entry: params_table 0 {'outport_bitmap': {'value': (2, 2)}}
Query Table Entry: match_table 1 {'eth_src': {'mask': 281474976710655, 'value': (2, 48)}}
Query Table Entry: params_table 1 {'outport_bitmap': {'value': (1, 2)}}
Query Table List: ['match_table', 'params_table']

Now go back to the Mininet terminal, and run pingall. It should be able to complete the pings and we should see the following output.

*** Ping: testing ping reachability
h1 -> h2 
h2 -> h1 
*** Results: 0% dropped (2/2 received)