Developing in NOX - noxrepo/nox-classic GitHub Wiki

Table of Contents

Overview

There are really only two basic concepts one has to learn to work effectively with NOX, the Component system, and the Event system. This section focuses on the development of these two. If you haven't already done so, please make sure you go through their respective descriptions as well as the Main/Introduction pages.

Developing Components

NOX components can be written in either C++ or Python (or both). At the time of this writing, the Python API to the network is more mature and therefore more friendly for new NOX developers. We recommend that unless the component being developed has serious performance requirements, that developers start with Python.

NOX component code resides in src/nox/. In this folder, depending on the type of the component, they are distributed in the coreapps, netapps and webapps subfolders. In general, each NOX component has its own directory, however this isn't strictly necessary (for example src/nox/apps/examples/ contains multiple apps).

Building a C++ only component

Lets use the hub program (src/nox/coreapps/hub/) as an example of how to extend NOX. Hub is just that, a dumb network hub which floods packets out of all ports except the incoming port. For every packet received by NOX, the hub floods the packet and then adds a flow entry in the OpenFlow switch to flood all subsequent packets from the same flow.

Class Hub provides an example of a simple component. All components must have the following construction:

    class Hub
        : public Component
    {
    public:
         Hub(const Context* c, const xercesc::DOMNode*) : Component(c){ }
    
        void configure(const Configuration*) {
        }
    
        void install()
        { }
    };
    
    REGISTER_COMPONENT(container::Simple_component_factory<Hub>, Hub);

A component must inherit from Class component, have a constructor matching hub's constructor, and include a REGISTER_COMPONENT macro with external linkage to aid the dynamic loader. The methods 「configure」 and 「install」 are called at load time, configure first before install, and are used to register events and register event handlers.

Components must also have a meta.xml file residing in the same directory as the component. On startup, NOX search the directory tree for meta.xml files and uses them to determine what components are available on the system and their dependencies. For C++ components, the component <library></library> value must match the name of the shared library.

Simple components generally register for events in the install method and perform their functions in the event handlers. Take for example hub, which registers to be called for each packet received by NOX for any switch on the network.:

    void install()
    {
        register_handler<Packet_in_event>(boost::bind(&Hub::handler, this, _1));
    }

Event handling and registration is described further below.

Components can communicate through events or directly. In order to access a component directly, you must have a handle to it. To do this, use the resolve method (inherited by your app class from Component). Say you want to get a pointer to the topology component. Then the call should look something like:


Building a Python only component

Pure python components are much simpler to construct than C++ components. As an example, see src/nox/apps/examples/pyloop.py. A Python component must have the following construction:

    class foo(Component):
    
        def __init__(self, ctxt):
            Component.__init__(self, ctxt)
    
        def install(self):
            # register for event here
            pass
    
        def getInterface(self):
            return str(foo)
        
    def getFactory():
        class Factory:
            def instance(self, ctxt):
                return foo(ctxt)
    
        return Factory()

You may optionally add a configure method which is called in the same order as for C++ (before install on startup). The following steps should be all that is needed to build a bare-bones python component for NOX.

Add your .py file to src/nox/coreapps/examples/ Copy code from src/nox/coreapps/examples/pyloop.py (you need to mirror everything except for the code under the install method) Add your Python file(s) to NOX_RUNTIMEFILES in src/nox/apps/examples/Makefile.am Update src/nox/apps/examples/meta.json to include your new app. Make sure that 「python」 is a dependency (copying is the best approach). After you're done, recompile following the same 3 steps (the build/ directory is already there now)

Pointers:

  • The core python API is in nox/lib/core.py and nox/lib/util.py.
  • To get a handle to another component, use the Component.resolve(..) method on the class or interface to which you want a handle. For example:
    from nox.app.examples.pyswitch import pyswitch
    self.resolve(pyswitch)

Building an integrated C++/Python component

Building integrated components (those exposed to both C++ and Python) is rather complex at the moment. It will require some familiarity with swig. To see how this is done, take a look at src/nox/apps/simple-c-py-app/.

Developing Events

Once again, make sure you are familiar with the concept of [NOX] before proceeding to this section.

Building custom Events

Registering for Events

Registering for events is simple in both C++ and Python.

In C++, use the Component::register_handler method (src/builtin/component.cc). It expects the name of the event, and an Event_handler (which must be of type boost::function). Relevant C++ definitions can be found in src/nox/coponent.hh. NOX's C++ API relies heavily on boost::bind and boost::fuctions, if you are not familiar with these you can learn more form the Boost library documentation. The following example shows how one might register for a packet in event:

    void install()
    {
        register_handler<Packet_in_event>(boost::bind(handler, this, _1));
    }

All handlers must return a Disposition (defined in src/include/event.hh) which is either CONTINUE, meaning to pass the event to the next listener, or STOP, which will stop the event chain.

Registering a handler in Python is similar to the C++ interface. To do so, use the register_handler interface defined in src/nox/lib/core.py. For example:

    def install(self):
        self.register_handler (Packet_in_event.static_get_name(), handler)

Posting events

Any application can create and post events for other applications to handle using the following method:

    void post(Event*) const;

Events passed to post() are assumed to be dynamically allocated and are freed by NOX once fully dispatched.

Posting an event is simple. For example:

    post(new Flow_in_event(flow, *src, *dst, src_dl_authed, src_nw_authed, dst_dl_authed, dst_nw_authed, pi));

Posting events from Python is nearly identical. The following code is from src/nox/apps/discovery/discovery.py:

    e = Link_event(create_datapathid_from_host(linktuple[0]), create_datapathid_from_host(linktuple[2]),
              linktuple[1], linktuple[3], action)
    self.post(e)

Posting timers

In NOX, all execution is event-driven (this isn't entirely true, but unless you want to muck around with native threads, it's a reasonable assumption). Applications can ask NOX to call a handler after some amount of time has lapsed, forming the basis for timer creation. This functionality is also done using the post method:

    Timer post(const Timer_Callback&, const timeval& duration) const;

For example, registering a method to be called every second might look like:

    timeval tv={1,0}
    post(boost::bind(&Example::timer, this), tv);

Or in Python:

    post_callback(1, timer)

Compiling your new component

Make sure you add your component's name under the desired package in configure.ac.in Rerun ./boot, ../configure, make

In the makings: NOX C/C++ Tutorial (Counting Pings)

⚠️ **GitHub.com Fallback** ⚠️