Christian Dickmann
Applied Computer Science student at the University of Göttingen

 NSIS
 Homepage
 HOWTOs
 Testbed setup
 Create your own NSLP
 
Create your own NSLP

This tutorial will guide you through creating an initial NSLP similar to the Ping tool NSLP shipped with our NSIS implementation.

Contents

1. Prerequirements
2. Start creating your own NSLP
3. Extend the NSLP messages with a new object
4. Use the new object to send a new message type
5. Add a state machine to the NSLP
6. Extend HopDiscoveryMessage to gather IP address of all nodes along the path

1. Prerequirements

You should set up a testbed like the one descriped here. You should at least perform Test I of that tutorial.
You need PHP5 and automake 1.7.
TODO

2. Start creating your own NSLP

Create NSLP from skeleton and register the created NSLP

In this section we start creating a new NSLP named SampleNslp. The initial step is to create the basic file structure from a skeleton NSLP. To do so, please change to the nslp/ directory and run the script createFromSkeleton.php with the large and the short name as the arguments. For example:
php -f createFromSkeleton.php SampleNslp sample
This will create a directory called sample and initital NSLP code. Before compiling or testing the newly created NSLP you need to register it.
  • Open the file library/NslpIDs.h and add the following line at the proper place (of course you can use a different ID):
    #define SAMPLENSLP_NSLP_ID 999
  • Open the file configure.in in the root directory of NSIS. At the end of the file you will find a list of Makefiles. You need to add your one. The line you need to insert looks like this one:
            nslp/sample/Makefile \
After registering your NSLP you need to update the buildsystem. Run the following two command in the root directory of NSIS:
./autogen.sh
./configure
This will run automake, autoconf, autoheader and run the configure script. If you compiled NSIS with parameters after ./configure, use these parameters here too. Now you should find a Makefile in the nslp/sample/ directory.

Change to this directory and run make:
make
After compiling your NSLP you should find two new binaries (nsis-sampled and nsis-sample) in the bin/ directory.

What is the new NSLP capable of?

  • It has a daemon that runs on the routers and a client (a command line tool) that is supposed to run on the initiator
  • The client is able to trigger sending a sample message
  • The daemon will recognize this trigger and really construct and send the sample message
  • The daemon will forward the message to the receiver and from there back to initiator
  • The daemon will inform the client about the returned sample message

Testing the new NSLP

Run bin/nsis on all network nodes that should take part in the test. You should use the same setup that you used in the initial test of the ping tool NSLP. In addition run bin/nsis-sampled on all those network nodes. The nsis daemon should confirm that the sample NSLP connected.
On the initior you now need to run the NSLP client to trigger a sample message:
bin/nsis-sample <destinationIP>
Confirm that the client shows a returncode of 0.
Congratulations, your first NSLP actually works.

How does the client side of the new NSLP work?

The executable main()-function is contained in sample-client.cpp. It transforms the provided command line arguments into calls to the SampleNslpClient class contained in the clientapi directory.
The SampleNslpClient class is the API to your NSLP. This class could be used in an complex application using your NSLP. It communicates with the NSLP daemon over unix sockets and utilizes the helper methods of clientapi/SampleNslpCommunicator.cpp.

How does the server side of the new NSLP work?

The main component of the server/daemon is the SampleNslpServer class. It initializes and manages the communication with NSLP clients and with the API to GIST (called NSLP API). It also provides helper methods used across your NSLP. The most important parts are:
  • handleClientSocket(): Here the messages send by SampleNslpClient are received. A proper SampleNslpFsmData object is created and the request is passed to the global SampleNslpFsm object.
  • handleRecvMessage(): The messages received by GIST are passed to this method by the NSLP API. Again a proper SampleNslpFsmData object is created and passed to the SampleNslpFsm.
The second major component of the server is the, already mentioned, SampleNslpFsm. Fsm in general is the short form of "finite state machine", but the skeleton NSLP does not contain a state machine yet. Instead the skeleton contains the structure so that a real FSM can be added easily. Later in this tutorial, a small FSM will be build into the SampleNSLP. The SampleNslpFsm class in contained in the logic directory and serves as the central place for any NSLP logic. Therefore sending, forwarding and receiving messages is handled here.
The SampleNslpFsm class uses objects of the container class SampleNslpFsmData to get a proper context for all methods provided by the Fsm.
Last but not least, the NSLP message and objects classes are an important component of the NSLP. The skeleton already provides a basic message structure:
  • An NSLP message starts with a common header
  • After the header the message contains objects
  • These objects all start with a StandardObjectHeader (containing the length and type of the following object)
One sample object is provided in the skeleton. Is it called SampleNslpSampleObject and contains a 32 bit unsigned integer used as a sequence number. How to create new objects is discussed in the next chapter of this tutorial.

3. Extend the NSLP messages with a new object

The new object

The new object created in this chapter of the tutorial is just ment as an example. It is named HopCount object and consists of a 16 bit HopCount and 16 bit padding (simply left empty).

What needs to be done?

  • Extend the objects/objects.xml with our new object and run objects/objects.php to create the source files.
  • Extend message/SampleNslpMessage.cpp/.h to recognize the new object.
  • Add the new object to Makefile.am

Extend objects/objects.xml

The objects.xml file contains a list of objects, their names and byte format. This XML is transformed to C++ classes by objects.php. The resulting classes are capable of composing and parsing these objects, as well as providing getter and setter access to the fields.
Example:
<object>
	<name>SampleNslpHeader</name>
	<type>commonheader</type>
	<elements>
		<element>
			<name>version</name>
			<type>unsigned char</type>
			<length>8</length>
		</element>
		<element>
			<name>length</name>
			<type>unsigned char</type>
			<length>8</length>
		</element>
		<element>
			<length>16</length>
		</element>
	</elements>
</object>
The name-tag specifies the name of the class that is created for this object.
The type-tag is optional and needs to be supplied for special objects, like type "commonheader". Normal objects (like our new one) must ommit the type-tag.
The fields of the object are provided in the elements-tag.
Each field is represented by an element-tag, which itself is composed of:
  • The names of fields can be specified with the name-tag and are used for getter and setter methods.
  • The type of fields can be specified with the type-tag. Valid types are the following:
    • bool (default: 1 bit)
    • unsigned char (default: 8 bit)
    • unsigned short (default: 16 bit)
    • unsigned int (default: 32 bit)
    • in_addr (default: 32 bit) - IPv4 address
    • in6_addr (default: 128 bit) - IPv6 address
  • The length of the fields can be adjusted with the length-Tag.
  • Reserved fields can be created with <element><length>8</lengh></element>
  • If you want to apply a bitmask to a field, you need to specify the bitmask-tag. e.g.: <bitmask>0x0fff</bitmask>
  • A complex example: 1 bit flag, 3 bit reserved, 12 bit integer value. You would write such a case this way:
    <element>
    	<name>the_flag</name>
    	<type>bool</type>
    	<length>4</length>
    </element>
    <element>
    	<length>3</length>
    </element>
    <element>
    	<name>the_number</name>
    	<type>unsigned short</type>
    	<bitmask>0x0fff</bitmask>
    	<length>12
    </element>
The object we want to create is named HopCountObject and consists of a 16 bit HopCount and 16 bit reserved bits. Therefore, the XML we need to add looks like:
<object>
	<name>SampleNslpHopCountObject</name>
	<elements>
		<element>
			<name>hopcount</name>
			<type>unsigned short</type>
			<length>16</length>
		</element>
		<element>
			<length>16</length>
		</element>
	</elements>
</object>

Extend class SampleNslpMessage

The message class must support the newly created SampleNslpHopCountObject.
We start in the SampleNslpMessage.h file:
  • First of all we need to add the include
    #include "objects/ SampleNslpHopCountObject.h"
  • Then we need to add a member that holds a pointer to a HopCount object
    SampleNslpHopCountObject * hopCountObject;
  • Now we need to create a method that is capable of adding a HopCount object to a message. This method should look like:
void addHopCountObject(SampleNslpHopCountObject * hopCount) {
	this-> hopCountObject = hopCount; addObject(hopCount);
}
  • The last step in the header file is to add hopCountObject to the destructor.
    delete hopCountObject;

After changing the header file, we change the SampleNslpMessage.cpp file:
  • The pointer that we created in the header file needs to be initialized in the resetObjects() method.
    hopCountObject = NULL;
  • The very last step is to add our HopCount object to the message parsing routine found in the analyze()-Method. Inside this method you find a switch-case for all known objects. We need to add one case:
case SAMPLENSLPHOPCOUNTOBJECT:
	hopCountObject = new SampleNslpHopCountObject(buffer + 
		offset, objectPayloadLength);
	break;
Now your message is capable of handling the new object (just one HopCount object per message).

Add the newly created file to Makefile.am

The new file objects/SampleNslpHopCountObject.cpp needs to be added to the list of source files in the Makefile.am.
Afterwards you need to run autogen.sh and configure again. Now you can try to run "make" in your NSLP directory.

4. Use the new object to send a new message type

What needs to be done?

Add sendHopDiscoveryMessage() to SampleNslpClient

Change sample_client.cpp to use new message type

Add sendHopDiscoveryMessage() to SampleNslpFsm

Add handler for new client trigger to SampleNslpServer

Handle HopDiscoveryMessage in intermediate Nodes

Pass discovered HopCount to the client

Testing


5. Add a state machine to the NSLP

Goal of this chapter

In this section we add a finite state machine to the SampleNSLP. As an example we add a new message type to authorize ourselfs in a first step and only then we are allowed to get the HopCount. Does not really makes sense, but illustrates how things work.

What needs to be done?

Create a new SampleNslpAuthorizationObject that consists of a 32 bit integer password.
Register this object in the message class. (see Chapter 3 on how to do so)
Add the FSM to our NSLP.
Add a new autorization message type that contains only the autorization object. (only in SampleNslpFsm)
Add the logic

Add the FSM to our NSLP

Add sendAuthorizationMessage() to SampleNslpFsm

Add handler for AuthorizationMessages in intermediate nodes

Change the logic of HopCount forwarding

Only forward when we are in state authorized

Add support in the client

Send HopDiscovery message directly
Send HopDiscovery after sending Authorization message

Test


6. Extend HopDiscoveryMessage to gather IP address of all nodes along the path