Table Of Contents

Previous topic

Application Development by Example

Next topic

Application Index

NOX Core API

This section describes NOX’s core API. This is the basic interface applications use to gain access to network events, control network components, and interface with each other.

Basic Concepts

  • All NOX applications are subclasses of “Component” (src/nox/component.hh for C++, nox/apps/lib/core.py for Python). The Component class definitions contain the full core API.
  • NOX applications can register to be called back on various events, which are either thrown by NOX (in the case of a low-level OpenFlow event), or by another application.
  • The C++ end uses a cooperative thread model for handling asynchronous events. For simple apps, most of this should be hidden under the covers.
  • The Python support uses a pure event-based, asynchronous model based on twisted.

C++

The following documentation refers to the public methods in src/nox/component.hh.

Registering callbacks for a network event

The primary mechanism for gaining access to network events is to register a handler using one of the following methods:

void register_handler(const Event_name&, const Event_handler&) const;

inline void register_handler<Event>(const Event_handler& h) const;

The following example registers a callback for all incoming packets to NOX:

// NOTE: example only, not a valid NOX Component
class Example{
public:
Disposition print(const Event& e)
{
    using namespace std;
    const Packet_in_event& pi = assert_cast<const Packet_in_event&>(e);
    cout << " Received packet in on port " << pi.in_port << endl;
    return CONTINUE; // keep processing the packet
}


// at application load time, register handler
void install()
{
    register_handler<Packet_in_event>(
        Packet_in_event::static_get_name(),
        boost::bind(&Example::print, this, _1));
}
}; // class Example

An event handler is a boost::function and must return a Disposition and accept a NOX Event (src/include/event.hh). Return values can be either of the following:

  • STOP do not pass the event on to any more handlers
  • CONTINUE continue processing the event

NOX core event types are defined in files in src/include/. These include:

  • Packet_in_event Called for every packet received by NOX
  • Datapath_join_event Called each time a switch connects to NOX
  • Datapath_leave_event Called each time a switch disconnects from NOX
  • Flow_expired_event Called for each flow entry that has expired on the network

All other events are generated and thrown by applications.

In many cases an application is only interested in a particular type of traffic from the network (for example, only DNS and DHCP). For this, NOX provides a convenience function which allows the application to specify the header values for the packets it is interested in.:

Rule_id register_handler_on_match(uint32_t priority,
                                  const Packet_expr &,
                                  Pexpr_action) const;

Packet_expr is defined in src/include/expr.hh. The handler (Pexpr_action) differs from the standard handler in that it does not return a Disposition value. When NOX receives a packet, only matching handler(s) with the lowest priority value will be invoked.

For example, registering only for TCP packets looks like:

// only call on TCP packets
Packet_expr expr;
uint32_t val = ethernet::IP;
expr.set_field(Packet_expr::DL_TYPE,  &val);
val = ip_::proto::TCP;
expr.set_field(Packet_expr::NW_PROTO, &val);
register_handler_on_match(100,
                          expr,
                          boost::bind(&Example::tcp_packet_handler, this, _1));

Posting events for other applications

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

void post(Event*) const;

Warning

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 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:

void timer(){
    using namespace std;
    cout << "One second has passed " << endl;
    timevale tv={1,0}
    post(boost::bind(&Example::timer, this), tv);
}

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

Managing switch flow tables

Applications manage forwarding on the network by adding and deleting flow entries in switches. NOX exposes the full functionality supported by the OpenFlow management protocol. The general function doing this is:

int send_openflow_command(const datapathid&, const ofp_header*,
                          bool block) const;

OpenFlow message formats and definitions are contained in src/include/openflow.hh.

Warning

Unfortunately this method is quite low level at the moment and requires callers to construct their own OpenFlow messages (yuck). We will provide convenience functions for the common OpenFlow operations in a future release. Until then, you can use src/nox/apps/switch/switch.cc as a guide to setting up a flow.

Sending packets

Applications can send packets on the network using one the following methods:

// Instruct a switch to send a packet it has buffered
int send_openflow_packet(const datapathid&, uint32_t buffer_id,
                         uint16_t out_port, uint16_t in_port,
                         bool block) const;

// Send a packet in a Buffer object out on the network
int send_openflow_packet(const datapathid&, const Buffer&,
                         uint16_t out_port, uint16_t in_port,
                         bool block) const;

The first method accepts a buffer_id and assumes that the switch is already buffering the packet. Unless otherwise instructed, switches buffer incoming packets and only send the first 128 bytes to the controller. The buffer_id is then passed to the application in a Packet_in_event. Use the first method to send this packet out again (see src/nox/apps/hub/hub.cc for an example).

The second method allows an application to construct and send an arbitrary packet out on the network.

Python

Warning

This section is incomplete. Refer to files in src/nox/apps/examples/ for guidance.

NOX’s Python API is defined in “core.py” in src/nox/lib/. It exposes the same functionality as the C++ API, but attempts to remove some of the complexity (e.g. more convenient methods to modify switch flow tables). Many of the C++ definitions needed to interact with NOX are exposed to Python in SWIG *.i files also located in src/nox/lib/. These include netinet and OpenFlow definitions. Events and components meanwhile are exposed in the *.i files in src/nox/apps/pyrt/.

A packet handling library has also been defined in src/nox/lib/packet/ for convenient packet construction and parsing.