= 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 [#new here]''' 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 }}} = 1.1 Installation, new version = #new The installation procedures have been significantly streamlined (e.g. to use apt). It is described in the [http://noxrepo.org/noxwiki/index.php/NOX_Installation 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: * [http://nemesis.sourceforge.net/ 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 === 1. 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 }}} 2. 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. [[BR]][[BR]] ref: http://www.mail-archive.com/nox-dev@noxrepo.org/msg01448.html 3. 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 ` 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. 4. 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: 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. 2. 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 }}} 3. 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 (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 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 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.