Tutorial >> Writing Your First Plugin | TOC |
We will first write the most basic mycounter plugin to count packets and return the packet counter when queried by the RLI via the CP. As such, it will behave exactly like a simplified form of the COUNTER plugin in ~onl/stdPlugins/. Although the plugin is very simple, it will demonstrate most of the basic plugin concepts.
Let's look at the mycounter-1100/mycounter.h file as produced by newplugin.pl. You will see that the header file:
In practice, the only functions that will require much new code are the functions to handle a packet and to handle a message from the CP. The amount of additional code depends on the nature of the plugin service. Since mycounter is very simple, even these two functions will not require much new code.
First, we extend the mycounter_instance structure in the mycounter.h file with the packet counter variable pkt_counter (we have marked the added lines of code with '+' in the left margin).
struct mycounter_instance { struct rp_instance rootinstance; // base class part + int pkt_count; };
Now, we add the code to zero the packet counter pkt_count in the function mycounter_create_instance( ) in the mycounter.c file. As shown below, we only need to add one line to the function.
struct rp_instance * mycounter_create_instance( struct rp_class *myclass, // points to class structure u_int32_t instanceid) // new instance identifier { struct mycounter_instance *myinst; // allocate memory for local instance struct MSR_PLUGIN_MALLOC(myinst,struct mycounter_instance *, sizeof(struct mycounter_instance), M_MSR, M_WAITOK); if (myinst == NULL) return NULL; // fill in instance pointers to local methods myinst->rootinstance.rpclass = &mycounter_class; myinst->rootinstance.handle_packet = mycounter_handle_packet; myinst->rootinstance.free_instance = mycounter_free_instance; myinst->rootinstance.bind_instance = mycounter_bind_instance; myinst->rootinstance.unbind_instance = mycounter_unbind_instance; myinst->rootinstance.handle_msg = mycounter_handle_msg; myinst->rootinstance.instanceid = instanceid; + myinst->pkt_count = 0; // initialization code return (struct rp_instance *)myinst; }
The only remaining code additions are in the functions mycounter_handle_packet and mycounter_handle_message. The memory deallocation code already in mycounter_free_instance is sufficient for our plugin. We make no code additions to the mycounter_bind_instance and mycounter_unbind_instance functions. If we wanted to zero the packet counter each time we rebound the instance to another filter, we could add code to one of these two functions.
Now, we add the code to the mycounter_handle_packet function to increment the packet counter when it is called.
void mycounter_handle_packet( struct rp_instance *this, // points to instance structure void *bufferList) // points to list of pkt buffers { struct COUNTER_instance *inst = (struct COUNTER_instance *)this; + inst->pkt_count++; }
The above code demonstrates a suttle point. The function is passed a pointer of type struct rp_class which is only that part of the instance structure known to the environment external to the plugin. But inside a plugin instance, we use the type struct mycounter_instance which does include both the base (or root) components and our addition (i.e., the packet counter).
We want the plugin to respond in the following manner:
Code | Command | Arguments |
---|---|---|
0 | Return (plugin ID, instance number) | None |
1 | Return the packet count | None |
2 | Return the packet count and then zero it | None |
all else | Return the packet count and then zero it | None |
Finally, we add the code to the mycounter_handle_message function to respond to commands from the CP.
int mycounter_handle_msg( struct rp_instance *this, // points to instance structure void *buf, // points to request/reply buffer u_int8_t flags, // flags u_int8_t seq, // sequence number u_int8_t *len) // IN: request is in buf[0] thru buf[*len/4-1] // OUT: reply is in buf[0] thru buf[*len/4-1] { struct mycounter_instance *inst = (struct mycounter_instance *)this; u_int32_t *vals = (u_int32_t *)buf; u_int32_t id = (u_int32_t)ntohl(*vals); u_int32_t cmnd = (u_int32_t)ntohl(*(vals + 1)); struct msr_bufhdr_t *hdr; switch (cmnd) { case 0: // Hello *vals = (u_int32_t)htonl(mycounter_ID); *(vals + 1) = (u_int32_t)htonl(id); *len = 2 * sizeof(u_int32_t); break; default: + *vals = (u_int32_t)htonl(inst->pkt_count); + if (cmnd >= 2) inst->pkt_count = 0; + *len = 1 * sizeof(u_int32_t); break; } return 0; }
A message is just an array of integers that is large enough to fit into a single AAL0 ATM cell; i.e., 12 32-bit words (48 bytes). The first word contains the fields that are passed in the parameters flags, seq and *len. The remaining 11 integer words are passed through the *buf pointer parameter. The *len parameter indicates the number of bytes starting at *buf that contain data in the request message and in the reply message; i.e., the request buffer is reused for the reply buffer and is overwritten.
The mycounter_handle_msg function does not use the two variables flags and seq. However, it is worthwhile now explaining why they are there. The NSP command protocol uses a single ATM cell to transmit a command to an SPC and expects a single ATM cell in reply. The seq field is an 8-bit sequence number in the command protocol header. The flags field is an 8-bit flag field used in the command protocol. For example, one bit indicates if the cell contains a command while another bit indicates it contains a reply. These are primarily only of interest to the PCU.
By convention, word 0 contains the instance number of the plugin and word 1 contains the command or operation code. Both words are unsigned integers in Network-Byte-Order (NBO). id and cmnd are the corresponding values in Host-Byte-Order (HBO) and have be obtained from these first two words by calling the ntohl funtion. The remaining 9 words in the message are user-defined.
By convention, the command 0 is a 'hello' command in which the plugin returns the plugin ID followed by the instance number. All other command codes will return the packet count in word 0 of buf. In addition, if the command code is 2 or larger, the packet count will be zeroed.
We are done writing the plugin and should now try to find and fix any syntactic errors by compiling the code. Before doing that, review the modifications shown in the table below. You can also view the entire source code here.
File | Code Fragment | Modification |
---|---|---|
mycounter.h | struct mycounter_instance | Define packet counter variable pkt_count |
mycounter.c | mycounter_create_instance | Zero pkt_count |
|
mycounter_handle_packet | Increment pkt_count |
|
mycounter_handle_message | Handle commands to return/zero pkt_count |
Revised: Tue, Aug 15, 2006
Tutorial >> Writing Your First Plugin | TOC |