The ONL NPR Tutorial

NPR Tutorial >> Writing A Plugin TOC

New Window?

Quick Start

Contents

This page gives a recipe for how to write and test your own plugin; it tells you the "How" of writing plugin. The page Tour Of A Simple Plugin covers some of the "Why" and "What" parts of a simple plugin and Tour Of The Delay Plugin covers periodic computations. This page will begin by showing you how to make your own copy of the mycount plugin. Then, it leads you through the steps need to make a new plugin that is a small extension of the mycount plugin. In the example commands below, you will need to particularize the commands for your situation.

 

Compiling Your Own mycount Plugin

We assume below that you have logged into the onlusr host and that you are in your home directory. We will compile your own version of the mycount plugin. This should be straightforward since you will be starting with the source code of a predefined plugin and therefore should not be getting any compiler errors.

  1. Make your own plugin source code directory.
  2. 	mkdir npr-plugins		# your NPR plugin directory
    	cd npr-plugins
    	mkdir mycount			# your own mycount plugin directory
    
  3. Now, get the three files mycount.c, plugin_helpers.h and Makefile from the mycount directory.
  4. cd mycount
    cp  ~onl/npr/plugins/mycount/{mycount.c,plugin_helpers.h,Makefile} .
    
  5. Compile the plugin, saving stdout and stderr in the file make.log. (This will take about 1 or 2 minutes.)
  6. 	make > make.log 2>&1		# bash
    	make >& make.log		# csh
    
  7. See if there were any errors or warnings.
  8. 	egrep 'error|warn' make.log
    
    You should see about 10 lines that say there are "0 error(s)".
  9. Briefly look at the output from the compile step using a command like more, less or your favorite editor (not shown).
  10. 	more make.log
    

There should be files in the subdirectories list/ and uof/. This is an indication that object files and executables were created by the make command. The contents of the uof/ directory should look like this when you enter the command ls uof:

onlusr> ls uof
mycount.uof         mycount.uof_1_2800  mycount.uof_2_2805  mycount.uof_4_2800
mycount.uof_0_2800  mycount.uof_1_2805  mycount.uof_3_2800  mycount.uof_4_2805
mycount.uof_0_2805  mycount.uof_2_2800  mycount.uof_3_2805
This output shows that the make command created 10 mycount executables. It created two executables for each of the five plugin MEs: one for an IXP 2800 and one for an IXP 2805. This shotgun approach to producing executables is taken because it has to produce executables for all load possibilities. You have now created your own plugin and can not load it into any of the five plugin MEs.

The next section will show you how to load and test this plugin. This plugin will use eight hardware-supported threads: six packet handling threads, one control message thread and one periodic computation thread. Actually, the periodic computation thread doesn't do anything useful. The underlying ONL plugin framework used by the six packet handling threads ensure that packets are handled in FIFO order even though the threads execute concurrently. The concurrency occurs because of the structure of the main() function and the settings in the Makefile. The details are described in the next tutorial page Tour Of A Simple Plugin.

 

Testing Your Own mycount Plugin

[[ mycount-1npr.png Figure ]]

Now you need to test your own mycount plugin. We'll use the 1-NPR configuration (above). We will install a filter at input port 1.0 that directs traffic to a mycount plugin running on plugin microengine 0. Everytime a meta-packet arrives to the plugin, the plugin will increment its two packet counters and then forward the meta-packet to output port 1 for transmission. If the plugin works, we should be able to send packets through the plugin at a low rate using the ping command and see that:

We'll also show you how to use the debugging facilities to print out debug messages from the plugin.
  1. Commit a 1-NPR configuration with hosts connected to ports 1.0 and 1.1 (i.e., n1p0 and n1p1). Use default routing at all of the input ports.

  2. Verify that you can send packets from n1p0 to n1p1 by logging into n1p0 and issuing the ping command:
  3. 	$n1p0> ping -c 5 n1p1
    
  4. Tell the RLI where your personal plugin directory is located.
  5. Note that even though there is a predefined mycount plugin directory at ~onl/npr/plugins/mycount/, we will be putting our personal version in a subdirectory of our home directory; i.e., ~/npr-plugins/mycount/.
  6. Install your own mycount plugin into plugin ME 0.
    If you now select Edit => Add Plugin in the Plugin Table, the RLI should display all predefined plugins as well as the plugins in your personal plugin directory.
  7. Install a filter at input port 1.0 to direct all packets to the plugin and then on to output port 1.1.
  8. Verify that you can still send packets from n1p0 to n1p1 by issuing the ping command from host $n1p0.
  9. 	$n1p0> ping -c 5 n1p1
    
  10. Send a message to the plugin to get the packet count.
  11. [[ send-get-resize.png Figure ]]
  12. Create a chart to monitor the absolute value of PluginCounter 0 on ME 0.
  13. [[ monitoring-PluginCounter-resize.png Figure ]]
    Recall that the mycount plugin keeps the packet count in both the pkt_count variable and PluginCounter 0. The difference is that the value of PluginCounters is visible for charts through the NPR menu item Monitoring => PluginCounter.
  14. Send a message to the plugin to zero the two packet counters pkt_count and PluginCounter 0.

  15. Tell the RLI where to record debug messages.
  16. We will now test the plugin debug message facility. Debug messages are recorded in a log file specified by the user if the user tells the RLI where to record debug messages and the plugin calls the onl_api_debug_message() function. In the mycount plugin, the onl_api_debug_message() function is only called if the debug_on variable is 1 (the default value).

    [[ debug-out-resize.png Figure ]]
  17. Send some more ping packets from n1p0 to n1p1 and look in the debug message log file.
  18. The log file shows that five packets were handled by the plugin and that the messages were logged about every 1 second. Notice that the packet numbers are preceded by the character 'x' which indicates that the number is a hexadecimal number.

  19. Tell the plugin to stop outputting debug messages.
  20. Tell the plugin to resume outputting debug messages.
Congratulations! You have successfully compiled and tested your own mycount plugin.
 

Creating Your Own Plugin Called zzz

We now address the issue of really creating your own plugin. This section shows you that the mycount Makefile needs to be updated to reflect the name of the new plugin. The next section will lead you through making a few changes to the mycount source code.

Are you still awake?

 

Modifying Your zzz Plugin

Now, let's make a few simple modifications to the zzz plugin:

These changes will require that we modify only two functions: handle_pkt_user() and handle_msg(). Most of the code can be created by copying the lines of code that refer to the variable pkt_count and then changing the name to total_count. There are two exceptions in addition to the ones cited in the next two subsections: Keep in mind, that most of the code in the mycount plugin would be found in any other plugin that follows our plugin framework. Code deletions should not be done unless you really understand their implications. That's why all of the changes described below are code additions or small modifications. We don't discuss large modifications to the code until the page Tour Of The Delay Plugin.

In the explanation to follow, you will see the following examples that are specific to the IXP programming environment (and therefore, may appear unusual) and to the ONL plugin framework:

The page Tour Of A Simple Plugin provides more details. We now show the changes required to implement the above changes. These changes are marked with "<<<<<" in the code below.

The Global Variable Changes

The only change required here is to add the declaration of the new variable total_count.

	// my global declarations
	__declspec(shared gp_reg) unsigned int pkt_count;
	__declspec(shared gp_reg) unsigned int total_count;		<<<<<
	__declspec(shared gp_reg) unsigned int debug_on;
We copied the pkt_count declaration and changed the name to total_count putting it in a general-purpose register that will be shared by the handle_pkt() and handle_msg threads.

The init_plugin_user() Changes

The only change required is to inialize the value of total_count to 0.

	void plugin_init_user()
	{
	    if(ctx() == 0)	// only thread 0 should do the initialization
	    {
		pkt_count = 0;
		total_count = 0;					<<<<<
		debug_on = 1;
	
		sleep(timeout);
		helper_plugin_cntr_zero( 0 );
	    }
	}
This function is called by main(). But note that there will be eight main() functions on the ME, one for each thread. But only hardware context 0 will execute the above code.

The handle_pkt_user() Changes

The handle_pkt() function is called whenever one of the six packet handling threads gets a packet. That function calls handle_pkt_user() to do user-specific processing.

If we want to output a debug message any time that the value of total_count is incremented to a value that is evenly divisible by 10, we will have to modify the handle_pkt_user() function so that it:

1	void handle_pkt_user() {
2	    __declspec(local_mem) char dbgmsg[28]	= "got pkt x";
3	    __declspec(local_mem) char pkt_count_str[9];
4	    __declspec(local_mem) char space_str[2]	= " ";		<<<<<
	
5	    ++pkt_count;
6	    ++total_count;						<<<<<
7	    if( debug_on ) {
8		onl_api_int2str( pkt_count, pkt_count_str );
9		strcat_lmem(dbgmsg, pkt_count_str);
10		if( total_count%10 == 0 ) {				<<<<<
11		    strcat_lmem( dbgmsg, space_str );			<<<<<
12		    onl_api_int2str( total_count, pkt_count_str );	<<<<<
13		    strcat_lmem(dbgmsg, pkt_count_str);			<<<<<
14		}							<<<<<
15		onl_api_debug_message(msgNextBlock, dbgmsg);
16	    }
	
17	    onl_api_plugin_cntr_inc(pluginId, 0);	// Incr global plugin cntr 0
18	}

Lines 6, 10 and 14 should be obvious. Line 4 declares space_str[2] to be the C-string containing the space character followed by the null byte and resides in local memory. Lines 12-13 look like lines 8-9 and concatenates the hexadecimal ASCII representation of total_count to the debug message after appending a space character. (Note that we said hexadecimal, not decimal.) Tour Of A Simple Plugin explains the purpose for the onl_api_int2str() function.

The handle_msg_user() Changes

The handle_msg() function is called whenever the control message handling thread gets a control message from the Xscale control processor. These messages are generated as a result of the RLI Plugin Table menu item Edit => Send Command to Plugin. The mycount plugin recognizes three commands: z(ero) counts, toggle d(debug) flag, and g(et) counts.

We want to modify handle_msg() so that whenever it gets the g control message, it will reply with both the value of pkt_count and total_count. This is a simple change since the idea is similar to the debug message changes that we made to handle_pkt_user() except that the counter values will be in decimal format instead of hexadecimal format.

1	void handle_msg()
2	{
3	    // assume messages are at most 8 words for now
4	    ... declarations deleted ...
5	    __declspec(local_mem) char space_str[2]	= " ";		<<<<<
6	    	... code deleted ...
7	    dl_source_message( msgFromBlock, message );
8	    	... code deleted ...
9	    if( in_msgstr[0] == 'z' ) {	
10	    	... code deleted ...
11	    } else if( in_msgstr[0] == 'g' ) {
12		helper_ultodec_lmem( pkt_count, pkt_count_str );
13		strcpy_lmem( out_msgstr, pkt_count_str );
14		strcat_lmem( out_msgstr, space_str( ) );		<<<<<
15		helper_ultodec_lmem( total_count, pkt_count_str );	<<<<<
16		strcat_lmem( out_msgstr, pkt_count_str );		<<<<<
17		if( onl_api_str2intarr(out_msgstr, &message[1]) < 0 ) { return; } 
18	    } else { ... code deleted ...  }
19	
20	    	... code deleted ...
21	    dl_sink_message(msgNextBlock, message);
22	}

These changes are straightforward since lines 15-16 are the total_count counterparts to those for pkt_count in lines 12-13. Note though that lines 12 and 15 use the helper_ultodec_lmem() function instead of the onl_api_int2str() function used in handle_pkt_user(). That's because helper_ultodec_lmem() converts from unsigned long to ASCII decimal using local memory parameters instead of to hexadecimal.

Testing The Changes

You should now be able to test the new zzz plugin in much the same manner that you tested the mycount plugin earlier. The only difference is that now there will be an extra field in the output of the g command and there will be extra debug messages due to the total_count variable.


 Revised:  Thu, Nov 13, 2008 

  
  

NPR Tutorial >> Writing A Plugin TOC