wiki:Internal/OpenFlow/Controllers/Nox

Version 8 (modified by akoshibe, 14 years ago) ( diff )

NOX - Network OS

NOX is an OpenFlow controller/ controller development platform. Here we'll use the "destiny" (v0.8) branch of NOX from the Git repository. As of now, a copy of the docs for v0.6 can be found under ./html in my home directory on external2. I shall move this to another, more appropriate place.

Note: in this documentation, ${NOXPATH} is the arbitrary path to your working nox directory. No such variable actually exists.

1 installation

  1. Install git, build-essential, doxygen (for up-to-date NOX docs)
    apt-get install git-core build-essential doxygen
    
  2. Pull NOX from git repo
    cd ${noxpath}
    git clone git://noxrepo.org/nox
    
  3. Install dependencies
    sudo apt-get install autoconf automake g++ libtool python python-twisted swig libboost-dev libxerces-c2-dev libssl-dev make libboost-filesystem-dev libboost-test-dev python-dev
    
  4. Switch to the proper branch and build
    git checkout -b destiny origin/destiny
    ./boot.sh
    mkdir build
    cd build
    ../configure
    make
    
  5. generate documentation
    cd doc/doxygen            <<--from build directory, not ${NOXPATH}/nox
    make html
    

2. using NOX

2.1. starting up NOX

nox_core is used to start the controller and to load any scripts. It is located under ${NOXPATH}/nox/build/src . For example

./nox_core -v -i ptcp:6633 switch packetdump

Will load the "learning switch" script. It will show up as "lt-nox_core" under ps -ef.

2.2. creating a component (in C++)

The information on how to do this can be found in /html/Howto.html under the doxygen generated docs for nox. As the steps require file creation, compilation, ect, you may need root privelages on the machine. The rough steps are as follows:

  1. Run nox-new-c-app.py from coreapps, netapps, or webapps (all three directories are found in ${NOXPATH}/nox/src/nox ).
    cd nox/src/nox/coreapps
    /home/openflow/nox/src/scripts/nox-new-c-app.py -v cnf_test
    

nox-new-c-app.py basically creates a directory containing the framework for your application (Makefile, meta.json, ect), basing it on coreapps/simple_c_app. Your app gets created in whichever directory you run nox-new-c-app.py from; in this case we created a new app "cnf_test" in directory coreapps.

  1. run boot.sh and configure so nox can find and load the app when it starts up:
    ./boot.sh                       #this is found in the root of your nox directory e.g. ${NOXPATH}/nox/boot.sh
    cd build
    ../configure
    make
    
  1. to test if your app is there, you can watch out for it being loaded when you do a dry run of nox_core:
    root@node1-4:~/nox/build/src# ./nox_core -i ptcp:6633 -v
    00001|nox|INFO:Starting nox_core (/home/openflow/nox/build/src/.libs/lt-nox_core)
    ...
    00006|pyrt|DBG:Loading a component description file 'nox/coreapps/cnf_test/meta.json'.
    

or try loading it:

 ./nox_core -i ptcp:6633 -v "cnf test"

note that any underscores in the name of your app become spaces - e.g. "cnf_test" becomes "cnf test"

If you see the following after issuing the above command, you have a working framework:

00046|openflow|DBG:Passive tcp interface bound to port 6633
00047|nox|INFO:nox bootstrap complete
00048|openflow|DBG:Passive tcp interface received connection 
00049|openflow|DBG:stream: negotiated OpenFlow version 0x01 (we support versions 0x01 to 0x01 inclusive, peer no later than version 0x01)
...

3. Customizing your component

All applications under nox are found in either netapps., coreapps, or webapps. Each app is contained in a directory that includes code for the applications' modules (e.g. routing modules implementing specific algorithms), and a list, named meta.json, used by nox to find and load modules at startup.

By itself, your new component only knows how to initiate a channel with an OpenFlow switch, and to start up the "liveness check" echo requests. This section is a compilation of information on the nox libraries that can be used to define your own controller.

3.1 The configure function.

The configure function allows you to register the events that the module will respond to via the Disposition type function (more detail later on regarding this), and to define options for your application.

3.1.1. starting modules with flags

When starting nox_core, flags can be specified by the application name, followed by an '=', then your flag(s):

./nox_core -v -i ptcp:6633 switch="noflow"

I'm guessing if it can take multiple options, you can string multiple flags by delimiting each option with a comma or another '='.

3.1.2. registering events.

This is done with the register_handler which takes your event's name and allows you to specify a NOX event to bind to it:

 register_handler<Flow_in_event>
        (boost::bind(&SPRouting::handle_flow_in, this, _1));

Here, a Flow_in_event (defined in NOX libraries) is taken as an argument to the module specific Disposition type function handle_flow_in.

This snippet is taken from the built-in routing module (netapps/routing/sprouting.cc, .hh) which makes an OF switch behave like a router. The sprouting module is fairly complex and can be used to see how a module is built; we'll be using pieces of this module (along with others where specified) throughout this page.

3.1.3. defining flags/options.

It seems customary to define and check for flags within configure function, but this doesn't have to be the case. For example, in sprouting, there is a separate function called validate_args. A more "traditional" way of doing this is through the Configuration object (found in nox/src/nox/component.hh):

class Configuration {
public:
    virtual ~Configuration();
    
    /* Retrieve a value of an XML configuration key. */
    virtual const std::string get(const std::string& key) const = 0;

    /* Return true if the XML key exists. */
    virtual const bool has(const std::string& key) const = 0;

    /* Return all XML keys. */
    virtual const std::list<std::string> keys() const = 0;
    
    /* Return all command line arguments of the component. */
    virtual const Component_argument_list get_arguments() const = 0;

    /* Return list of arguments. */
    virtual const hash_map<std::string, std::string> 
    get_arguments_list(char d1 = ',', char d2 = '=') const = 0;
};

This class allows you to input flags as described earlier in 3.1.1. Actually using the class involves something like this (from switch.cc).

Switch::configure(const Configuration* conf) {
...
   BOOST_FOREACH (const std::string& arg, conf->get_arguments()) {
        if (arg == "noflow") {
            setup_flows = false;
        } else {
            VLOG_WARN(log, "argument \"%s\" not supported", arg.c_str());
        }
    }
...

3.2. Event triggers

Event triggers allow you to define your controller's behavior. This is done by defining Disposition type functions that you may (or may not) have registered using register_handler. The configure function allows you to define which Dispositions your controller will immediately respond to based on inputs; Other, "unregistered" Disposition functions can be called from these functions that you register with configure.

3.2.1 The Disposition type

An Event trigger (Dispostiton function) is declared like this:

Disposition
SPRouting::handle_flow_in(const Event& e)
{
...

When actually called, the register_handler uses Boost's bind function to associate input flags with the arguments for this Disposition function.

Note: See TracWiki for help on using the wiki.