Difference between revisions of "TUT:Writing a Dynamically Loadable Object"
(→Prerequisites: Rephrased much of the section.) |
(→Introduction: Clarified the distinction between built-in and dynamically loaded MIB objects.) |
||
Line 1: | Line 1: | ||
− | This page describes how to build extension for Net-SNMP as <em>shared objects</em>, binary files that can be loaded by the SNMPd daemon directly and are executed as part of the daemon. This differs from the concept | + | This page describes how to build extension for Net-SNMP as <em>shared objects</em>, binary files that can be loaded by the SNMPd daemon directly and are executed as part of the daemon. This differs from the concept introduced in [[TUT:Writing a MIB Module|Writing a MIB Module]] in that the extension resides in its own binary file and is loaded by the agent <em>at runtime</em>. This adds the flexibility to add new functionality / MIBs <em>after</em> the agent has been compiled, enabling you to extent the daemon provided by a binary package without the need to roll your own modified package. |
+ | |||
+ | Yet another possibility is offered by <em>Subagents</em>, see [[TUT:Writing a Subagent|Writing a Subagent]]: Subagents are separate processes that do not share memory, file descriptors and so on with the daemon and must use <em>interprocess communication</em> (IPC) to communicate with the daemon. | ||
Writing dynamically loadable objects is interesting because you will have the entire API provided by Net-SNMP at your disposal, for example a caching infrastructure. Shared objects loaded this way usually get their configuration from the same configuration file the core daemon uses, which often is a nice thing. Disadvantages are that a programming mistake in your custom extension may crash the entire daemon and that your code is by design always executed as the same user the core daemon is executed as, i. e. potentially with unnecessary privileges — or too little, depending on your setup. | Writing dynamically loadable objects is interesting because you will have the entire API provided by Net-SNMP at your disposal, for example a caching infrastructure. Shared objects loaded this way usually get their configuration from the same configuration file the core daemon uses, which often is a nice thing. Disadvantages are that a programming mistake in your custom extension may crash the entire daemon and that your code is by design always executed as the same user the core daemon is executed as, i. e. potentially with unnecessary privileges — or too little, depending on your setup. |
Revision as of 21:15, 3 March 2009
This page describes how to build extension for Net-SNMP as shared objects, binary files that can be loaded by the SNMPd daemon directly and are executed as part of the daemon. This differs from the concept introduced in Writing a MIB Module in that the extension resides in its own binary file and is loaded by the agent at runtime. This adds the flexibility to add new functionality / MIBs after the agent has been compiled, enabling you to extent the daemon provided by a binary package without the need to roll your own modified package.
Yet another possibility is offered by Subagents, see Writing a Subagent: Subagents are separate processes that do not share memory, file descriptors and so on with the daemon and must use interprocess communication (IPC) to communicate with the daemon.
Writing dynamically loadable objects is interesting because you will have the entire API provided by Net-SNMP at your disposal, for example a caching infrastructure. Shared objects loaded this way usually get their configuration from the same configuration file the core daemon uses, which often is a nice thing. Disadvantages are that a programming mistake in your custom extension may crash the entire daemon and that your code is by design always executed as the same user the core daemon is executed as, i. e. potentially with unnecessary privileges — or too little, depending on your setup.
Contents
Prerequisites
While not strictly necessary, you'll probably have an easier time building a shared object if you start with an already functioning MIB module (extension) as described in Writing a MIB Module. This section of the tutorials will assume you have a working extension build directly into the daemon already and tells you how to move that out of the daemon and into a shared object.
For demonstration purposes, we'll refer to some example MIB objects and code: the NET-SNMP-TUTORIAL-MIB MIB, and the example MIB module and it's header file.
Note: The dlmod
code is based on the UCD-DLMOD-MIB
. It resides in the ucdExperimental
name-space, but since nothing has changed since 1999 it's pretty safe to assume this interface is stable. You can find the MIB in mibs/UCD-DLMOD-MIB.txt
in the source-code distribution.
The Net-SNMP package must have been built with dynamically loadable module support for the following to work. You should therefore enable the UCD MIB when configuring the sources:
$ ./configure --with-mib-modules="ucd_snmp $OTHER_MIBS" $OTHER_OPTIONS
Besides the right MIB, you need of course support for shared objects. This is enabled with the --enable-shared
argument of configure
, but should be automatically enabled if your system supports dynamically loaded objects. You can check for support in your agent but looking at the output of the snmpd -H
command for the "dlmod" token. If its listed, the compiled agent supports it.
Note: All command line options below assume you have an appropriately setup ~/.snmp/snmp.conf
file that allows you to not have to specify a SNMP version number, community name, username, or whatever else in order to talk to your agent. The agent, of course, must have a matching /usr/local/share/snmp/snmpd.conf
file (or equivalent).
Here are the files discussed in this example so you can download them:
File | Description |
---|---|
Makefile | A simple makefile used to build the projects |
NET-SNMP-TUTORIAL-MIB.txt | The MIB we'll be writing code for in the various pieces of the agent extension tutorial |
nstAgentPluginObject.h | The MIB module's header file |
nstAgentPluginObject.c | The MIB module's C source code |
Initialization
After loading the shared object to memory, the object loader will look for an initialization function inside the shared object. The name of this function is init_name
, where "name" is the name of your extension. The name of the example module is "nstAgentPluginObject", so the loader will look for a function with the following prototype:
void init_nstAgentPluginObject (void);
There's a complementary function, called deinit_name
, which is called when the module is unloaded, for example when the daemon is shutting down. Unsurprisingly, the prototype of the example deinit-function is:
void deinit_nstAgentPluginObject (void);
These are the only two functions called by the object loaded. All other functions (and module-global variables) therefore should be declared static
.
You can check the names of currently loaded modules using the UCD-DLMOD-MIB::dlmodName
OID.
Configuration
As mentioned in the introduction, you can register own configuration options which extend the daemon's configuration. To do so, you need to provide two callback functions which are called when appropriate: One that handles a configuration statement, and one that cleans up when necessary. A short example is given below and registers the foobar option:
static const char *global_foobar = NULL; … static void config_handle (const char *key, char *value) { if (strcasecmp ("foobar", key) == 0) { char *tmp = strdup (value); if (tmp != NULL) { free (global_foobar); global_foobar = tmp; } } else if … } /* void config_handle */ static void config_free (void) { free (global_foobar); global_foobar = NULL; } … snmpd_register_config_handler ("foobar", config_handle, config_free, "The foobar option does something incredible!");
Do not just assign the value
pointer to a global variable or dreadful things may happen!
Writing the module
The next steps are basically the same as those steps outlined in Writing a MIB Module, i. e. register one or more data sets at some OIDs, for example using the netsnmp_register_table_data_set, see the data_set.c example. Please see the introductory documentation.
- First off we must get the Makefile file, the nstAgentPluginObject.h file, and the nstAgentPluginObject.c file.
- make nstAgentPluginObject.so
- Start the snmpd and watch the dlmod and nstAgentPluginObject modules interact using the debugging flag (this assumes you already have access control set up properly for your agent):
- % snmpd -f -L -DnstAgentPluginObject,dlmod
- In another window, test to make sure that the agent doesn't currently support the nstAgentPluginObject (if you get different results running this command you need to recompile the net-snmp agent without the nstAgentPluginObject mib module compiled in directly):
- % snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0
- nstAgentPluginObject.0 = No Such Object available on this agent at this OID
- Then, run snmpset to create a new row in the dlmod table:
- % snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create
- dlmodStatus.1 = create(6)
- See that the row was created:
- % snmptable localhost UCD-DLMOD-MIB::dlmodTable
- SNMP table: dlmodTable
- dlmodName dlmodPath dlmodError dlmodStatus
- unloaded
- Then set the properties of the row up to point to our new object and to give it a name:
- % snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s "nstAgentPluginObject" UCD-DLMOD-MIB::dlmodPath.1 s "/path/to/nstAgentPluginObject.so"
- dlmodName.1 = "nstAgentPluginObject"
- dlmodName.1 = "/path/to/nstAgentPluginObject.so"
- % snmptable localhost UCD-DLMOD-MIB::dlmodTable
- SNMP table: dlmodTable
- dlmodName dlmodPath dlmodError dlmodStatus
- nstAgentPluginObject /path/to/nstAgentPluginObject.so unloaded
- Finally, load the shared object into the running agent:
- % snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load
- dlmodStatus.1 = loaded(1)
- % snmptable localhost UCD-DLMOD-MIB::dlmodTable
- SNMP table: dlmodTable
- dlmodName dlmodPath dlmodError dlmodStatus
- nstAgentPluginObject /path/to/nstAgentPluginObject.so loaded
- If everything above was done correctly, then the following command should work and will access the shared object's data:
- % snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0
- nstAgentPluginObject.0 = INTEGER: 3
Loading via the snmpd.conf file
You can also load shared objects using the "dlmod" token in the snmpd.conf file by putting a line like this in your snmpd.conf file:
dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so
The first argument specifies the shared object's module name (UCD-DLMOD-MIB::dlmodName) and second argument specifies the full pathname of the shared object file.
Tutorial Sections
About the SNMP Protocol
These tutorial links talk about SNMP generically and how the protocol itself works. They are good introductory reading material and the concepts are important to understand before diving into the later tutorials about Net-SNMP itself.
- How SNMP Works: About the protocol itself (GETs, GETNEXTs, etc)
- What data is in SNMP: All about SNMP Management Information Bases (MIBs)
- Securing SNMP: How to use the SNMP protocol securely
Net-SNMP Command Line Applications
These tutorial pages discuss the command line tools provided in the Net-SNMP suite of tools. Nearly all the example commands in these tutorials works if you try it yourself, as they're all examples that talk to our online Net-SNMP test agent. Given them a shot!
- snmptranslate: learning about the MIB tree.
- snmpget: retrieving data from a host.
- snmpgetnext: retrieving unknown indexed data.
- snmpwalk: retrieving lots of data at once!
- snmptable: displaying a table.
- snmpset: peforming write operations.
- snmpbulkget: communicates with a network entity using SNMP GETBULK request
- snmpbulkwalk: retrieve a sub-tree of management values using SNMP GETBULK requests.
- snmptrap: Sending and receiving traps, and acting upon them.
- Traps/informs with SNMPv3/USM: Sending and receiving SNMPv3/USM TRAPs and INFORMs
- Sending Traps/Informs via AgentX: Sending notifications from the command line through snmpd
- Common command line options:
- Writing mib2c config files
Application Configuration
All of our applications support configuration to allow you to customize how they behave.
Net-SNMP Daemons
Net-SNMP comes with two long-running daemons: a SNMP agent (snmpd) for responding to management requests and a notification receiver (snmptrapd) for receiving SNMP notifications.
- SNMP Agent (snmpd) Configuration
- SNMP Notification Receiver (snmptrapd)
- Agent Monitoring
Coding Tutorials
Net-SNMP comes with a highly flexible and extensible API. The API allows you to create your own commands, add extensions to the agent to support your own MIBs and perform specialized processing of notifications.
- Client / Manager Coding Tutorials
- Agent Coding Tutorials
- The Agent Architecture page might be worth reading before or after the agent coding tutorials, and describes how the Agent Helpers work under the hood.
- Writing a mib module to serve information described by an SNMP MIB, and how to compile it into the net-snmp snmpd agent.
- Writing a Dynamically Loadable Object that can be loaded into the SNMP agent.
- Writing a Subagent that can be run to attach to the snmpd master agent.
- Writing a perl plugin to extend the agent using the NetSNMP::agent module.
- Writing shell scripts to extend the agent
- Using mib2c to help write an agent code template for you
- Header files and autoconf
Debugging SNMP Applications and Agents
All our tools and applications have extensive debugging output. These tutorials talk about how the debugging system works and how you can add your own debugging statements to you code:
- Debugging output printed using the -D command line option
- Using -Ddump to display packet breakdowns
- Debugging using GDB
Operating System Specific Tutorials
- Building With Visual Studio 2005 Express
- Building Net-SNMP 64-bit with Visual C++ 2010 Express
- Net-Snmp on Ubuntu
- Net-SNMP and lm-sensors on Ubuntu 10.04
- Net-SNMP for windows: