Version 10 (modified by 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 (OLD METHOD)
for updated install instructions for v0.9(zaku), go here
- Install git, build-essential, doxygen (for up-to-date NOX docs)
apt-get install git-core build-essential doxygen
- Pull NOX from git repo
cd ${noxpath} git clone git://noxrepo.org/nox
- 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
- Switch to the proper branch and build
git checkout -b destiny origin/destiny ./boot.sh mkdir build cd build ../configure make
- generate documentation
cd doc/doxygen <<--from build directory, not ${NOXPATH}/nox make html
1.1 Installation, new version
The installation procedures have been significantly streamlined (e.g. to use apt). It is described in the NOX wiki, but it will be repeated here for completeness.
Base system
NOX was built on an Ubuntu 10.10 server (with sshd enabled) install with the following additions:
Window manager:
- apt packages: ckermit git chromium-browser xinit icewm xterm vlan
Tarballs for packet injection to test NOX modules:
- nemesis
- Libnet-1.0.2a (found on same page, must be installed before building nemesis)
For the testbed topology:
- additional Ethernet interface (for OpenFlow channel)
The switch is a NEC IP880/S3640 with OpenFlow v 1.0 enabled firmware.
The process
- as root:
cd /etc/apt/sources.list.d sudo wget http://openflowswitch.org/downloads/debian/nox.list sudo apt-get update sudo apt-get install nox-dependencies
- add the following to the end of
/usr/lib/python2.6/dist-packages/twisted/internet/base.py
, before__all__ = []
:def _handleSigchld(self, signum, frame,_threadSupport=platform.supportsThreads()): from twisted.internet.process import reapAllProcesses if _threadSupport: self.callFromThread(reapAllProcesses) else: self.callLater(0, reapAllProcesses)
This is to make pyoxidereactor.py happy - it assumes that Python takes care of signal handling, which, in the newer versions, does not. The tabs should match with the rest of the file since Python is quite picky.
ref: http://www.mail-archive.com/nox-dev@noxrepo.org/msg01448.html
- download and build (The install was done in /opt fro this example):
git clone git://noxrepo.org/nox cd nox ./boot.sh mkdir build/ cd build/ ../configure make -j 5
This will install the latest version of NOX available from the main branch (v0.9 as of this documentation). If you want to pull a specific version of NOX, you can do a git checkout -b <name> <branch location>
after the initial invocation of git. For example, if you want to use v0.8(destiny) instead of v0.9, you can issue the following commands:
cd nox/ git checkout -b destiny origin/destiny
before running boot.sh
.
To see the available branches, you can use the command git branch
from the nox directory with the flag -r
, for "remote":
root@nox-gp:/opt/nox# git branch -r origin/HEAD -> origin/zaku origin/destiny origin/dev/destiny-fast origin/openflow-0.8.9 origin/openflow-0.9 origin/openflow-1.0 origin/zaku
And choose your pick from the list.
- generate documentation. From the build directory:
cd doc/doxygen make html
And point your browser to index.html under doc/doxygen/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:
- 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.
- run
boot.sh
andconfigure
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
- 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.