

<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://net-snmp.sourceforge.io/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Octo</id>
		<title>Net-SNMP Wiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://net-snmp.sourceforge.io/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Octo"/>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php/Special:Contributions/Octo"/>
		<updated>2026-05-01T17:50:48Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.26.3</generator>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=Talk:TUT:Writing_a_MIB_Module&amp;diff=3754</id>
		<title>Talk:TUT:Writing a MIB Module</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=Talk:TUT:Writing_a_MIB_Module&amp;diff=3754"/>
				<updated>2009-03-10T13:01:44Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: Added tasks for &amp;quot;A simple scalar attached to a variable&amp;quot;.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Tasks ==&lt;br /&gt;
&lt;br /&gt;
=== A simple scalar attached to a variable ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tasks&amp;gt;&lt;br /&gt;
[ ] Explain the return value of &amp;lt;em&amp;gt;netsnmp_register_int_instance&amp;lt;/em&amp;gt;.&lt;br /&gt;
&amp;lt;/tasks&amp;gt;&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3751</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3751"/>
				<updated>2009-03-05T09:57:10Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: /* Initialization */ Clarify what the problem with multiple loads is.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to build extension for Net-SNMP as &amp;lt;em&amp;gt;shared objects&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;at runtime&amp;lt;/em&amp;gt;. This adds the flexibility to add new functionality&amp;amp;nbsp;/ MIBs &amp;lt;em&amp;gt;after&amp;lt;/em&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Yet another possibility is offered by &amp;lt;em&amp;gt;Subagents&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;interprocess communication&amp;lt;/em&amp;gt; (IPC) to communicate with the daemon.&lt;br /&gt;
&lt;br /&gt;
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.&amp;amp;nbsp;e. potentially with unnecessary privileges ­— or too little, depending on your setup.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
While not strictly necessary, you&amp;#039;ll probably have an easier time building a shared object if you start with an already functioning &amp;lt;em&amp;gt;MIB module&amp;lt;/em&amp;gt; (extension) as described in [[TUT:Writing a MIB Module|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.&lt;br /&gt;
&lt;br /&gt;
For demonstration purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; The &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; code is based on the &amp;lt;code&amp;gt;UCD-DLMOD-MIB&amp;lt;/code&amp;gt;. It resides in the &amp;lt;code&amp;gt;ucdExperimental&amp;lt;/code&amp;gt; name-space, but since nothing has changed since 1999 it&amp;#039;s pretty safe to assume this interface is stable. You can find the MIB in &amp;lt;code&amp;gt;mibs/UCD-DLMOD-MIB.txt&amp;lt;/code&amp;gt; in the source-code distribution.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --with-mib-modules=&amp;quot;ucd_snmp $OTHER_MIBS&amp;quot; $OTHER_OPTIONS&lt;br /&gt;
&lt;br /&gt;
Besides the right MIB, you need of course support for shared objects. This is enabled with the &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; argument of &amp;lt;code&amp;gt;configure&amp;lt;/code&amp;gt;, 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 &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
After loading the shared object to memory, the &amp;lt;em&amp;gt;object loader&amp;lt;/em&amp;gt; will look for an initialization function inside the shared object. The name of this function is &amp;lt;code&amp;gt;init_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, where &amp;quot;name&amp;quot; is the name of your extension. The name of the example module is &amp;quot;nstAgentPluginObject&amp;quot;, so the loader will look for a function with the following prototype:&lt;br /&gt;
&lt;br /&gt;
 void init_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s a complementary function, called &amp;lt;code&amp;gt;deinit_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, 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:&lt;br /&gt;
&lt;br /&gt;
 void deinit_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
These are the only two functions called by the object loaded. All other functions (and module-global variables) therefore should be declared &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
It is important to note that nothing prevents the agent from a second &amp;quot;load&amp;quot; of the same shared object. The module isn&amp;#039;t actually loaded a second time, but the initialization function is run again. Modules should be able to handle that, for example by checking if they were already initialized when returning without further actions if so. The same applies to the de-initialization functions.&lt;br /&gt;
&lt;br /&gt;
Further when the last unload happens the module is unloaded and so the code disappears. When this happens everything registered with the agent from the module must be unregistered since not doing so is an open invitation to core dumps.&lt;br /&gt;
&lt;br /&gt;
You can check the names of currently loaded modules using the &amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt; OID.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
As mentioned in the introduction, you can register own configuration options which extend the daemon&amp;#039;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 &amp;lt;em&amp;gt;foobar&amp;lt;/em&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
 static const char *global_foobar = NULL;&lt;br /&gt;
 …&lt;br /&gt;
 static void config_handle (const char *key, char *value)&lt;br /&gt;
 {&lt;br /&gt;
   if (strcasecmp (&amp;quot;foobar&amp;quot;, key) == 0)&lt;br /&gt;
   {&lt;br /&gt;
     char *tmp = strdup (value);&lt;br /&gt;
     if (tmp != NULL)&lt;br /&gt;
     {&lt;br /&gt;
       free (global_foobar);&lt;br /&gt;
       global_foobar = tmp;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
   else if …&lt;br /&gt;
 } /* void config_handle */&lt;br /&gt;
 &lt;br /&gt;
 static void config_free (void)&lt;br /&gt;
 {&lt;br /&gt;
   free (global_foobar);&lt;br /&gt;
   global_foobar = NULL;&lt;br /&gt;
 }&lt;br /&gt;
 …&lt;br /&gt;
 snmpd_register_config_handler (&amp;quot;foobar&amp;quot;,&lt;br /&gt;
     config_handle, config_free,&lt;br /&gt;
     &amp;quot;The foobar option does something incredible!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Do &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; just assign the &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; pointer to a global variable or dreadful things may happen!&lt;br /&gt;
&lt;br /&gt;
== Writing the module ==&lt;br /&gt;
&lt;br /&gt;
The next steps are basically the same as those steps outlined in [[TUT:Writing a MIB Module|Writing a MIB Module]], i.&amp;amp;nbsp;e. register one or more data sets at some OIDs, for example using the [http://www.net-snmp.org/dev/agent/group__table__dataset.html#ga14 netsnmp_register_table_data_set], see [http://www.net-snmp.org/dev/agent/data__set_8c-example.html the data_set.c example]. Please see [[TUT:Writing a MIB Module|the introductory documentation]].&lt;br /&gt;
&lt;br /&gt;
== Compiling and linking the shared object ==&lt;br /&gt;
&lt;br /&gt;
Building shared objects for Net-SNMP works just like building any other shared object. If you have not done that so far, you should probably read your compilers documentation on the subject. When using the &amp;lt;em&amp;gt;GNU Compiler Collection&amp;lt;/em&amp;gt; (GCC), you will most likely need the &amp;lt;code&amp;gt;-fPIC -shared&amp;lt;/code&amp;gt; flags.&lt;br /&gt;
&lt;br /&gt;
You should use the &amp;lt;code&amp;gt;net-snmp-config&amp;lt;/code&amp;gt; script to determine additional compiler and linker flags. For example:&lt;br /&gt;
&lt;br /&gt;
 $ cc `net-snmp-config --cflags` -fPIC -shared -g -O0 -o nstAgentPluginObject.so nstAgentPluginObject.c `net-snmp-config --libs`&lt;br /&gt;
&lt;br /&gt;
You can find example &amp;lt;em&amp;gt;Makefiles&amp;lt;/em&amp;gt; at &amp;lt;code&amp;gt;agent/mibgroup/examples/Makefile.dlmod&amp;lt;/code&amp;gt; in the source-code distribution and at [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile]. Hopefully this&amp;#039;ll get you started.&lt;br /&gt;
&lt;br /&gt;
== Steps to test the shared object via runtime MIB configuration ==&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
== Loading via the snmpd.conf file ==&lt;br /&gt;
&lt;br /&gt;
A more common method of loading the shared object is to instruct the agent to load the extension at startup in the &amp;lt;code&amp;gt;snmpd.conf&amp;lt;/code&amp;gt; configuration file. This can be achieved using the &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; configuration option:&lt;br /&gt;
&lt;br /&gt;
 dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
&lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name, the second argument specifies the full pathname of the shared object file. The module name used here &amp;lt;em&amp;gt;must&amp;lt;/em&amp;gt; match the name of the initialization function, see [[#Initialization]].&lt;br /&gt;
&lt;br /&gt;
All custom configuration options, as described in [[#Configuration]], must &amp;lt;em&amp;gt;succeed&amp;lt;/em&amp;gt; the &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; statement.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[TUT:Writing a MIB Module]]&lt;br /&gt;
* [[Net-snmp extensions]]&amp;lt;br /&amp;gt;List of extensions, some of which are built as dynamically loaded objects.&lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=Talk:TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3750</id>
		<title>Talk:TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=Talk:TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3750"/>
				<updated>2009-03-05T09:53:46Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: Oh, right, dlopen behaves different from what I recalled.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;How is loading the shared object multiple times problematic? As long as non-static symbols of the are not exported by default, both objects should live in their private little happy place. Actually, I doubt that setting &amp;lt;code&amp;gt;RTLD_GLOBAL&amp;lt;/code&amp;gt; or similar would be a problem, because actually not symbol resolution takes place.. octo 21:45, 3 March 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
The problem is that dlopening the same module a second time will return a reference to the same object as the first dlopen, so both copies will work with the same static data. magfr 2009-03-04T22:07 UTC&lt;br /&gt;
* Oh, that&amp;#039;s right.. I should have checked &amp;lt;em&amp;gt;dlopen(3)&amp;lt;/em&amp;gt; first.. octo 09:53, 5 March 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=Talk:Tut:Extending_snmpd_using_perl&amp;diff=3746</id>
		<title>Talk:Tut:Extending snmpd using perl</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=Talk:Tut:Extending_snmpd_using_perl&amp;diff=3746"/>
				<updated>2009-03-04T07:32:05Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: Moved completed tasks here.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Thank you for your input&amp;lt;br&amp;gt;&lt;br /&gt;
Just write comments below&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;lt;tasks&amp;gt;&lt;br /&gt;
[x] Check handling of non-FQPN &amp;quot;perl do&amp;quot; files - ? searches @INC?&lt;br /&gt;
[x] Do external perl command files need to be executable or not?&lt;br /&gt;
&amp;lt;/tasks&amp;gt;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* Moved completed tasks to here. Maybe other tasks should be taken out of the normal text and put here instead, too? octo 07:32, 4 March 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=Tut:Extending_snmpd_using_perl&amp;diff=3745</id>
		<title>Tut:Extending snmpd using perl</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=Tut:Extending_snmpd_using_perl&amp;diff=3745"/>
				<updated>2009-03-04T07:29:16Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: /* Simple Example */ Improved the description of &amp;quot;do&amp;quot; and added &amp;quot;require&amp;quot;.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial is intended as a brief introduction to the technique of&lt;br /&gt;
embedding perl code within the &amp;#039;&amp;#039;snmpd&amp;#039;&amp;#039; agent (similar to how &amp;#039;&amp;#039;mod_perl&amp;#039;&amp;#039;&lt;br /&gt;
support allows you to embed perl directly into the apache web server). &lt;br /&gt;
&lt;br /&gt;
= Embedded perl =&lt;br /&gt;
&lt;br /&gt;
In order to use embedded perl within the agent, the package must have&lt;br /&gt;
been configured with this facility enabled:&lt;br /&gt;
&lt;br /&gt;
    configure  --enable-embedded-perl  .....&lt;br /&gt;
&lt;br /&gt;
Prior to release 5.4, this must be done explicitly when compiling the&lt;br /&gt;
code.  From 5.4 onwards, this is enabled by default.&lt;br /&gt;
&lt;br /&gt;
This mechanism allows you to include perl code within the snmpd.conf file,&lt;br /&gt;
using the basic syntax&lt;br /&gt;
&lt;br /&gt;
    perl  &amp;#039;&amp;#039;statements&amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
== Simple Example ==&lt;br /&gt;
&lt;br /&gt;
The traditional simple example would be the following &amp;lt;code&amp;gt;snmpd.conf&amp;lt;/code&amp;gt; fragment&lt;br /&gt;
&lt;br /&gt;
    perl  print &amp;quot;Hello, world!\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
Obviously, this can only server as a very basic example in the context of an SNMP agent.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;lt;tasks&amp;gt;&lt;br /&gt;
[ ] Provide workable simple examples of embedded perl - e.g. control of normal snmpd.conf directives&lt;br /&gt;
&amp;lt;/tasks&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The most common form of embedding Perl modules is to include an external Perl module:&lt;br /&gt;
&lt;br /&gt;
    perl  do  &amp;quot;/path/to/external/file.pl&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
The Perl &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt; function will look for the file using &amp;lt;code&amp;gt;@INC&amp;lt;/code&amp;gt; if it is not an absolute path. It will then read and parse the contents of that file, executing the global scope. The global &amp;lt;code&amp;gt;%INC&amp;lt;/code&amp;gt; will also be updated. That file therefore doesn&amp;#039;t need to be executable.&lt;br /&gt;
&lt;br /&gt;
A much cleaner and more Perl-like solution would be the use of a &amp;quot;real&amp;quot; Perl module:&lt;br /&gt;
&lt;br /&gt;
    perl  require Foo::Bar; Foo::Bar-&amp;gt;init (file =&amp;gt; &amp;quot;/path/to/somewhere&amp;quot;, debug =&amp;gt; 1);&lt;br /&gt;
&lt;br /&gt;
For more information on the behavior of &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;require&amp;lt;/code&amp;gt;, see the Perl documentation at:&lt;br /&gt;
&lt;br /&gt;
 $ perldoc -f do&lt;br /&gt;
 $ perldoc -f require&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
&lt;br /&gt;
There are a few things to be aware of with regard to the handling of&lt;br /&gt;
variables in embedded perl code.&lt;br /&gt;
&lt;br /&gt;
Firstly, the &amp;quot;do file.pl&amp;quot; mechanism is not the same as invoking a perl&lt;br /&gt;
program from the command line.  It just takes the name of the file to&lt;br /&gt;
run - not a command plus parameters.   So the snmpd.conf fragment&lt;br /&gt;
&lt;br /&gt;
    perl  do  &amp;quot;file.pl one two&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
won&amp;#039;t work as you might expect.&lt;br /&gt;
(It&amp;#039;s actually looking for a file called &amp;#039;&amp;#039;file.pl one two&amp;#039;&amp;#039;, which&lt;br /&gt;
almost certainly doesn&amp;#039;t exist!)&lt;br /&gt;
&lt;br /&gt;
However it is possible to mimic the behaviour of parameters by defining&lt;br /&gt;
variables in the perl statement, and then referring to these variables&lt;br /&gt;
in the external file:&lt;br /&gt;
&lt;br /&gt;
    perl  $argv1=&amp;quot;one&amp;quot;;  $argv2=&amp;quot;two&amp;quot;;  do &amp;quot;file.pl&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Secondly, the various &amp;lt;code&amp;gt;perl&amp;lt;/code&amp;gt; statements are executed in&lt;br /&gt;
order, so the fragment above could equally be represented as&lt;br /&gt;
&lt;br /&gt;
    perl  $argv1=&amp;quot;one&amp;quot;;&lt;br /&gt;
    perl  $argv2=&amp;quot;two&amp;quot;;&lt;br /&gt;
    perl  do &amp;quot;file.pl&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;lt;tasks&amp;gt;&lt;br /&gt;
[ ] Is this true??&lt;br /&gt;
[ ] Check the variable scoping behaviour&lt;br /&gt;
&amp;lt;/tasks&amp;gt;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
But the following doesn&amp;#039;t work :(&amp;lt;br&amp;gt;&lt;br /&gt;
- and will be a problem for the handler subroutine you will read about in a bit.&amp;lt;br&amp;gt;&lt;br /&gt;
If you are using $a in a subroutine, $a = 2 will be for both instances (the second instance has overwritten the $a = 1 with $a = 2).&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
perl $a=1; $b=1; do &amp;quot;perl.pl&amp;quot; &lt;br /&gt;
perl $a=2; $b=1; do &amp;quot;perl.pl&amp;quot; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
So watch out when passing parameters :)&lt;br /&gt;
&lt;br /&gt;
But the problem goes further ... &lt;br /&gt;
&lt;br /&gt;
Using $debugging=1?&amp;lt;br&amp;gt;&lt;br /&gt;
But if you have two programs and define $debugging=1 outside of the handler subroutine, then it will affect any other programs that have defined $debugging...&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And what if one defines a subroutine, say &amp;#039;helpfull&amp;#039; in more than one program: which one get&amp;#039;s called by the handler subroutine...&amp;lt;br&amp;gt;&lt;br /&gt;
- correct, the wrong one.&lt;br /&gt;
&lt;br /&gt;
== Initialisation ==&lt;br /&gt;
&lt;br /&gt;
If embedded perl support is enabled, then immediately before executing&lt;br /&gt;
the first &amp;lt;code&amp;gt;perl&amp;lt;/code&amp;gt; directive, the agent will execute the code&lt;br /&gt;
in the file &amp;lt;code&amp;gt;/usr/share/snmp/snmp_perl.pl&amp;lt;/code&amp;gt;.  By default,&lt;br /&gt;
this contains the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
##&lt;br /&gt;
## SNMPD perl initialization file.&lt;br /&gt;
##&lt;br /&gt;
&lt;br /&gt;
use NetSNMP::agent;&lt;br /&gt;
$agent = new NetSNMP::agent(&amp;#039;dont_init_agent&amp;#039; =&amp;gt; 1,&lt;br /&gt;
                            &amp;#039;dont_init_lib&amp;#039; =&amp;gt; 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The location of this initialisation file can be changed using the&lt;br /&gt;
snmpd.conf token &amp;lt;code&amp;gt;perlInitFile&amp;lt;/code&amp;gt;, and embedded perl&lt;br /&gt;
support can be turned off completely using the directive&lt;br /&gt;
&lt;br /&gt;
    disablePerl  true&lt;br /&gt;
&lt;br /&gt;
Question: &lt;br /&gt;
* one could write everything in snmp_perl.pl, but lets just make our own &amp;quot;do&amp;quot; for the time being.&lt;br /&gt;
* why is it there&lt;br /&gt;
&lt;br /&gt;
= Embedded Agent modules =&lt;br /&gt;
&lt;br /&gt;
One of the most important uses of embedded perl is to implement a MIB module&lt;br /&gt;
within the agent, using perl code (rather than a C code module).&lt;br /&gt;
Elements of this are covered in the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/perl/perl_module.pl|perl_module] tutorial page.&lt;br /&gt;
&lt;br /&gt;
This code can be used as a perl SNMP agent, perl subagent, or sourced directly within a agent containing embedded perl support. To make it work directly within your agent, save&lt;br /&gt;
this file somewhere on your local system, and use the following snmpd.conf fragment:&lt;br /&gt;
&lt;br /&gt;
    perl do &amp;quot;/path/to/perl_module.pl&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;lt;tasks&amp;gt;&lt;br /&gt;
[ ] Does this work as it stands, or are there any tweaks needed to the code?&lt;br /&gt;
&amp;lt;/tasks&amp;gt;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
There is also some documentation on the &amp;lt;code&amp;gt;NetSNMP::agent&amp;lt;/code&amp;gt; perl module&lt;br /&gt;
available at http://search.cpan.org/dist/NetSNMP-agent/agent.pm&lt;br /&gt;
&lt;br /&gt;
== Agent framework ==&lt;br /&gt;
&lt;br /&gt;
The basic structure of a perl MIB module implementation is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use NetSNMP::OID (&amp;#039;:all&amp;#039;); &lt;br /&gt;
use NetSNMP::agent (&amp;#039;:all&amp;#039;); &lt;br /&gt;
&lt;br /&gt;
    #&lt;br /&gt;
    # Handler routine to deal with SNMP requests&lt;br /&gt;
    #&lt;br /&gt;
sub myhandler {&lt;br /&gt;
    my  ($handler, $registration_info, $request_info, $requests) = @_;&lt;br /&gt;
&lt;br /&gt;
    for ($request = $requests; $request; $request = $request-&amp;gt;next()) { &lt;br /&gt;
        #&lt;br /&gt;
        #  Work through the list of varbinds&lt;br /&gt;
        #&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
    #&lt;br /&gt;
    # Associate the handler with a particular OID tree&lt;br /&gt;
    #&lt;br /&gt;
    my $rootOID = &amp;quot;.1.3.6.1.4.1.8072.999&amp;quot;;&lt;br /&gt;
    my $regoid = new NetSNMP::OID($rootOID); &lt;br /&gt;
    $agent-&amp;gt;register(&amp;quot;my_agent_name&amp;quot;, $regoid, \&amp;amp;myhandler);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reference material mentioned above has more information about what these&lt;br /&gt;
functions do, and how they should handle different types of request.&lt;br /&gt;
&lt;br /&gt;
== GET requests ==&lt;br /&gt;
&lt;br /&gt;
The type of SNMP request can be retrieved using the&lt;br /&gt;
&amp;lt;code&amp;gt;$request_info-&amp;amp;gt;getMode()&amp;lt;/code&amp;gt; call, which can&lt;br /&gt;
be used to distinguish between GET and GETNEXT requests,&lt;br /&gt;
and the various phases of processing a SET request.&lt;br /&gt;
&lt;br /&gt;
The GET request is the simplest case, as the request will have&lt;br /&gt;
specified a particular OID.  All that the perl module has to do&lt;br /&gt;
is to return the value associated with this OID:&lt;br /&gt;
&lt;br /&gt;
    my $oid = $request-&amp;gt;getOID();&lt;br /&gt;
    if ($request_info-&amp;gt;getMode() == MODE_GET) {&lt;br /&gt;
        if ($oid == new NetSNMP::OID($rootOID . &amp;quot;.1.2.1&amp;quot;)) {&lt;br /&gt;
            $request-&amp;gt;setValue(ASN_OCTET_STR, &amp;quot;hello world&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
or indicate the appropriate error if this is not actually a&lt;br /&gt;
valid MIB instance:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;lt;tasks&amp;gt;&lt;br /&gt;
[ ] How to report noSuchInstance/Object in a perl module?&lt;br /&gt;
&amp;lt;/tasks&amp;gt;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The tasks of identifying valid OIDs, and providing the appropriate&lt;br /&gt;
value are the main issues facing the perl coder.&lt;br /&gt;
&lt;br /&gt;
== GETNEXT requests ==&lt;br /&gt;
&lt;br /&gt;
Processing a GETNEXT request (either individually or as part of&lt;br /&gt;
an &amp;lt;code&amp;gt;snmpwalk&amp;lt;/code&amp;gt; command) is basically similar to handling&lt;br /&gt;
a GET request.  But first, the MIB module must examine the OID&lt;br /&gt;
provided, and decide which is the next valid MIB instance:&lt;br /&gt;
&lt;br /&gt;
    my $oid = $request-&amp;gt;getOID();&lt;br /&gt;
    if ($request_info-&amp;gt;getMode() == &amp;#039;&amp;#039;&amp;#039;MODE_GETNEXT&amp;#039;&amp;#039;&amp;#039;) {&lt;br /&gt;
        if ($oid &amp;#039;&amp;#039;&amp;#039;&amp;amp;lt;&amp;#039;&amp;#039;&amp;#039; new NetSNMP::OID($rootOID . &amp;quot;.1.2.1&amp;quot;)) {&lt;br /&gt;
            &amp;#039;&amp;#039;&amp;#039;$nextOID = $rootOID.&amp;quot;.1.2.1&amp;quot;;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
and then return this OID, together with the corresponding value:&lt;br /&gt;
&lt;br /&gt;
            &amp;#039;&amp;#039;&amp;#039;$request-&amp;gt;setOID($nextOID);&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
            $request-&amp;gt;setValue(ASN_OCTET_STR, &amp;quot;hello world&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== SET requests ==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;lt;tasks&amp;gt;&lt;br /&gt;
[ ] Describe SET processing&lt;br /&gt;
&amp;lt;/tasks&amp;gt;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Scalar objects ==&lt;br /&gt;
&lt;br /&gt;
== Tables ==&lt;br /&gt;
&lt;br /&gt;
== Parameters revisited ==&lt;br /&gt;
While going through the referance material, you will find:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
getRootOID ()&lt;br /&gt;
        Returns a NetSNMP::OID object that describes the registration&lt;br /&gt;
        point that the handler is getting called for (in case you&lt;br /&gt;
        register one handler function with multiple OIDs, which should&lt;br /&gt;
        be rare anyway)&lt;br /&gt;
&lt;br /&gt;
        $root_oid = $request-&amp;gt;getRootOID();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hmm, intresting...&amp;lt;br&amp;gt;&lt;br /&gt;
Why not make a hash of values to the perl programs. We presume that a number of perl agents will soon be available with different objectives and need a &amp;quot;standard&amp;quot; way of retrieving parameters from snmpd.conf.&amp;lt;br&amp;gt;&lt;br /&gt;
All the information could be hard coded in the perl agent (or at installation) but it would be nicer if the OID and which configuration file the agent uses could be defined at the least.&lt;br /&gt;
&amp;lt;p&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
perl  $regat = &amp;#039;.1.3.6.1.4.1.8072.999&amp;#039;;      \&lt;br /&gt;
      $root_oid = new NetSNMP::OID($regat);  \&lt;br /&gt;
      $config_file{root_oid} = &amp;quot;/etc/snmpd/snmpagent.conf&amp;quot;; \&lt;br /&gt;
      do &amp;quot;snmpagent.pl&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And reference $config_file{$root_oid} in the program.&lt;br /&gt;
&lt;br /&gt;
This could be made &amp;quot;the official&amp;quot; way to pass parameters in snmpd.conf&amp;lt;br&amp;gt;&lt;br /&gt;
Some of the work could be in a function library contained in ../share/snmp/snmp_perl.pl ....&amp;lt;br&amp;gt;&lt;br /&gt;
And be called by something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setconfig($regat, &amp;quot;/etc/snmpd/snmpagent.conf&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Giving an entry in snmpd.conf like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
perl $regat = &amp;#039;.1.3.6.1.4.1.8072.999&amp;#039;; \&lt;br /&gt;
     setconfig($regat, &amp;quot;/etc/snmpd/snmpagent.conf&amp;quot;); \&lt;br /&gt;
     do &amp;quot;/etc/snmpd/snmpagent.pl&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The snmpagent.pl could use a call to getRootID in order to referance the hash $config_file{$request-&amp;gt;getRootID()}&lt;br /&gt;
&lt;br /&gt;
= OXO Example =&lt;br /&gt;
== MODE_GET ==&lt;br /&gt;
&amp;quot;snmpget&amp;quot; is trivial as the requester knows what it wants and, if the agent has it, the reply is a simple hash lookup.&lt;br /&gt;
&lt;br /&gt;
== MODE_GETNEXT ==&lt;br /&gt;
&amp;quot;snmpwalk&amp;quot; is harder.&lt;br /&gt;
&lt;br /&gt;
The request almost knows what it wants, and the agent need&amp;#039;s to reply to anything that is in the area for the OID it has registered. &lt;br /&gt;
&lt;br /&gt;
Take $regat, &amp;#039;.1.3.6.1.4.1.8072.999&amp;#039;. We have a .1 extension that we would like to serve, with values in .1.1 .1.2 etc .2.1 .2.2 etc etc.&lt;br /&gt;
&lt;br /&gt;
The secret is to fill in the blanks in the hash for next OID&amp;#039;s where a value has not been assigned.&amp;lt;br&amp;gt;&lt;br /&gt;
So:&lt;br /&gt;
* In general, if $regat, $regat.1 or $regat.1.1 etc are requested, the agent should supply the next OID that has a value, and it&amp;#039;s value.&lt;br /&gt;
* Check for OID &amp;lt; $regat.1.1.1, reply with $regat.1.1.1 and it&amp;#039;s value.&lt;br /&gt;
* For $regat.1.1.&amp;lt;max&amp;gt; $regat.1.2.&amp;lt;max&amp;gt; etc, take a look at the hashs for OID&amp;#039;s and pay attention to how $OID_next{$prev_OID} = $this_OID is used in the example.&lt;br /&gt;
&lt;br /&gt;
== Input CSV ==&lt;br /&gt;
In order to give the example some &amp;quot;dynamic&amp;quot; data to display, an input &amp;quot;csv&amp;quot; is supplied&amp;lt;br&amp;gt;&lt;br /&gt;
-the format of the input csv is &amp;quot;made for the moment&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For example with $delimT=&amp;#039;=&amp;#039; and $delimV=&amp;#039;:&amp;#039; (the oidname is only used for documentation/comment).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
oidname1=4=value1:value2&lt;br /&gt;
oidname2=4=value3:value4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Which gives relative to $regat, with $extension = &amp;#039;1&amp;#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
NET-SNMP-MIB::netSnmp.999.1.1.1 = STRING: &amp;quot;value1&amp;quot;&lt;br /&gt;
NET-SNMP-MIB::netSnmp.999.1.1.2 = STRING: &amp;quot;value2&amp;quot;&lt;br /&gt;
NET-SNMP-MIB::netSnmp.999.1.2.1 = STRING: &amp;quot;value3&amp;quot;&lt;br /&gt;
NET-SNMP-MIB::netSnmp.999.1.2.2 = STRING: &amp;quot;value4&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
By the way:&amp;lt;br&amp;gt;&lt;br /&gt;
The 4 is ASN_OCTET_STR on my system. I would have liked to have written ASN_OCTET_STR as type &lt;br /&gt;
but my perl programming experience couldn&amp;#039;t help me in taking the ASN_OCTET_STR and use it directly in the reply: I would just like to take the type as written and not use a if else test sequence ... (Input please ...:) )&lt;br /&gt;
&lt;br /&gt;
== For example ==&lt;br /&gt;
Here is a &amp;quot;fun&amp;quot; one: walk passwd&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
perl print STDERR &amp;quot;Perl extensions:\n&amp;quot;&lt;br /&gt;
perl $debugging = &amp;#039;1&amp;#039;;&lt;br /&gt;
perl $verbose = &amp;#039;1&amp;#039;;&lt;br /&gt;
perl $regat = &amp;#039;.1.3.6.1.4.1.8072.999&amp;#039;; $extension = &amp;#039;1&amp;#039;;  \&lt;br /&gt;
     $mibdata = &amp;#039;/etc/passwd&amp;#039;; $delimT=&amp;#039;&amp;#039;; $delimV=&amp;#039;:&amp;#039;;   \&lt;br /&gt;
     do &amp;quot;/etc/snmp/snmpagent.pl&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that if $delimT=&amp;quot;&amp;quot; we assume the input is ASN_OCTET_STR and only parse for values with $delimV&lt;br /&gt;
&lt;br /&gt;
While I still have the following in my clipboard, the following, although nice to look at, doesn&amp;#039;t work :(&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
perl {&lt;br /&gt;
        $regat = &amp;#039;.1.3.6.1.4.1.8072.999&amp;#039;; $extension = &amp;#039;1&amp;#039;;&lt;br /&gt;
        $mibdata = &amp;#039;/etc/passwd&amp;#039;; $delimT=&amp;#039;&amp;#039;; $delimV=&amp;#039;:&amp;#039;;&lt;br /&gt;
        do &amp;quot;/etc/snmp/snmpagent.pl&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Code&amp;quot; : perl do ==&lt;br /&gt;
&amp;quot;snapshot&amp;quot; or see http://svn.berlios.de/wsvn/odp/trunk/bin/snmpagent.pl?op=file&amp;amp;rev=0&amp;amp;sc=0&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/perl &lt;br /&gt;
&lt;br /&gt;
########################################&lt;br /&gt;
#&lt;br /&gt;
# &lt;br /&gt;
# Owen Brotherwood, DK 2007 &lt;br /&gt;
# Based on original perl module example &lt;br /&gt;
# GNU General Public License V3 &lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
######################################### &lt;br /&gt;
&lt;br /&gt;
$program = $0;&lt;br /&gt;
&lt;br /&gt;
if (!defined($regat)) {&lt;br /&gt;
        help(&amp;#039;No $regat defined&amp;#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub help {&lt;br /&gt;
        my ($message) = @_;&lt;br /&gt;
        print STDERR &amp;#039;&lt;br /&gt;
ERROR: &amp;#039; .  $program . &amp;#039;:&amp;#039; . $message . &lt;br /&gt;
&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Here is some help ...&lt;br /&gt;
&lt;br /&gt;
        This program should be started from snmpd.conf, an example for allowing&lt;br /&gt;
        one to walk /etc/passwd would be when this program is /etc/snmp/snmpagent.pl:&lt;br /&gt;
                perl print STDERR \&amp;#039;Perl extentsions:\&amp;#039; . \n\&amp;quot;&lt;br /&gt;
                perl $debugging = \&amp;#039;1\&amp;#039;;&lt;br /&gt;
                perl $verbose = \&amp;#039;1\&amp;#039;;&lt;br /&gt;
                perl {$regat = \&amp;#039;.1.3.6.1.4.1.8072.999\&amp;#039;; $extension = \&amp;#039;1\&amp;#039;;   \&lt;br /&gt;
                      $mibdata = \&amp;#039;/etc/passwd\&amp;#039;; $delimT=\&amp;#039;\&amp;#039;; $delimV=\&amp;#039;:\&amp;#039;;  \&lt;br /&gt;
                      do \&amp;#039;/etc/snmp/snmpagent.pl\&amp;#039;;}&lt;br /&gt;
&lt;br /&gt;
        Use snmpd -f to see what is going on.&lt;br /&gt;
&lt;br /&gt;
        If $delimT is defined, the first two values are comment(for documentation)&lt;br /&gt;
            and type, for example 4.&lt;br /&gt;
        If $delimT is \&amp;#039;\&amp;#039;, ASN_OCTET_STR (4) is presummed.&lt;br /&gt;
&lt;br /&gt;
        So, with $delimV=\&amp;#039;:\&amp;#039; and $delimT=\&amp;#039;=\&amp;#039;:&lt;br /&gt;
                oidname1=4=value1:value2&lt;br /&gt;
                oidname2=4=value3:value4&lt;br /&gt;
&lt;br /&gt;
        The result of a snmpwalk with $regat = &amp;#039;.1.3.6.1.4.1.8072.999&amp;#039; and $extension = &amp;#039;1&amp;#039; would be:&lt;br /&gt;
                NET-SNMP-MIB::netSnmp.999.1.1.1 = STRING: &amp;quot;value1&amp;quot;&lt;br /&gt;
                NET-SNMP-MIB::netSnmp.999.1.1.2 = STRING: &amp;quot;value2&amp;quot;&lt;br /&gt;
                NET-SNMP-MIB::netSnmp.999.1.2.1 = STRING: &amp;quot;value3&amp;quot;&lt;br /&gt;
                NET-SNMP-MIB::netSnmp.999.1.2.2 = STRING: &amp;quot;value4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        NB: snmptable requires a MIB to work.&lt;br /&gt;
&lt;br /&gt;
        Owen Brotherwood, DK 2007&lt;br /&gt;
        GNU General Public License V3&lt;br /&gt;
&amp;#039;;&lt;br /&gt;
        die($message);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
use NetSNMP::OID (&amp;#039;:all&amp;#039;);&lt;br /&gt;
use NetSNMP::agent (&amp;#039;:all&amp;#039;);&lt;br /&gt;
use NetSNMP::ASN (&amp;#039;:all&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
sub my_snmp_handler { &lt;br /&gt;
            my ($handler, $registration_info, $request_info, $requests) = @_; &lt;br /&gt;
            my $request; &lt;br /&gt;
            my %my_oid = (); &lt;br /&gt;
        my @mibdata;&lt;br /&gt;
        my $ASN_OCTET_STR = 4;&lt;br /&gt;
# for this example, wasteful read test data in every time ... &lt;br /&gt;
    	open(MIB,$mibdata); &lt;br /&gt;
            @mibdata = &amp;lt;MIB&amp;gt;; &lt;br /&gt;
            close(MIB); &lt;br /&gt;
# we append .1 to $regat for the area which the test data is available&lt;br /&gt;
    	$base_oid = new NetSNMP::OID($regat . &amp;#039;.&amp;#039; . $extension); &lt;br /&gt;
# start taking in values &lt;br /&gt;
        undef($prev_oid); &lt;br /&gt;
        $jndex = 1; &lt;br /&gt;
        foreach $line (@mibdata) { &lt;br /&gt;
# fill the hash pipe &lt;br /&gt;
                chomp $line; &lt;br /&gt;
                if ($delimT != &amp;#039;&amp;#039;){&lt;br /&gt;
                        ($index_name, $index_type, $index_values) = split(/$delimT/, $line); &lt;br /&gt;
                }else{&lt;br /&gt;
                        $index_values = $line;&lt;br /&gt;
                        $index_name = &amp;#039;Unknown&amp;#039;;&lt;br /&gt;
                        $index_type = $ASN_OCTET_STR;&lt;br /&gt;
                }&lt;br /&gt;
                my @value = split(/$delimV/, $index_values); &lt;br /&gt;
                my $index = 1; &lt;br /&gt;
                foreach $mibit (@value) { &lt;br /&gt;
                        $this_oid = new NetSNMP::OID($base_oid . &amp;#039;.&amp;#039; . $jndex . &amp;#039;.&amp;#039; . $index); &lt;br /&gt;
                        $oid_type{$this_oid} = $index_type;&lt;br /&gt;
                        $oid_value{$this_oid} = $mibit; &lt;br /&gt;
                        $oid_index{$this_oid} = $index; &lt;br /&gt;
                        $oid_jndex{$this_oid} = $jndex; &lt;br /&gt;
                        if (defined($prev_oid)){ &lt;br /&gt;
                                $oid_next{$prev_oid} = $this_oid; &lt;br /&gt;
                        } &lt;br /&gt;
                        $prev_oid = $this_oid; &lt;br /&gt;
                        print STDERR &amp;quot;Loading $this_oid $oid_type{$this_oid}::$oid_value{$this_oid}  \n&amp;quot; if ($verbose); &lt;br /&gt;
                        $index++; &lt;br /&gt;
                } &lt;br /&gt;
                $jndex++; &lt;br /&gt;
        } &lt;br /&gt;
        $mjndex = $jndex;&lt;br /&gt;
        $mindex = $index;&lt;br /&gt;
# fill in some blanks&lt;br /&gt;
	for ($jndex = 1; $jndex &amp;lt; $mjndex; $jndex++) {&lt;br /&gt;
                $this_oid = new NetSNMP::OID($base_oid . &amp;#039;.&amp;#039; . $jndex);&lt;br /&gt;
                $next_oid = new NetSNMP::OID($this_oid . &amp;#039;.1&amp;#039;);&lt;br /&gt;
                $oid_next{$this_oid} = $next_oid;&lt;br /&gt;
        }&lt;br /&gt;
        for ($request = $requests; $request; $request = $request-&amp;gt;next()) { &lt;br /&gt;
                $oid = $request-&amp;gt;getOID(); &lt;br /&gt;
                print STDERR &amp;quot;$program @ $oid &amp;quot; if ($debugging); &lt;br /&gt;
                if ($request_info-&amp;gt;getMode() == MODE_GET) { &lt;br /&gt;
# easy to get &lt;br /&gt;
                        print STDERR &amp;quot; GET &amp;quot; if ($debugging); &lt;br /&gt;
                        if (exists $oid_value{$oid}) { &lt;br /&gt;
                                print STDERR &amp;quot;-&amp;gt;$oid_value{$oid}\n&amp;quot; if ($debugging); &lt;br /&gt;
                                $request-&amp;gt;setValue($oid_type{$oid}, $oid_value{$oid}); &lt;br /&gt;
                        }else{ &lt;br /&gt;
                                print STDERR &amp;quot; No value ...\n&amp;quot;; &lt;br /&gt;
                        } &lt;br /&gt;
                }elsif ($request_info-&amp;gt;getMode() == MODE_GETNEXT) { &lt;br /&gt;
# long way to walk &lt;br /&gt;
                        print STDERR &amp;quot; GETNEXT &amp;quot; if($debugging); &lt;br /&gt;
                        if (defined($oid_next{$oid})) { &lt;br /&gt;
                                $next_oid = $oid_next{$oid}; &lt;br /&gt;
                                $type_oid = $oid_type{$next_oid}; &lt;br /&gt;
                                $value_oid = $oid_value{$next_oid}; &lt;br /&gt;
                                $request-&amp;gt;setOID($next_oid); &lt;br /&gt;
                                $request-&amp;gt;setValue($type_oid, $value_oid); &lt;br /&gt;
                        }elsif ($oid &amp;lt;= $base_oid) { &lt;br /&gt;
                                $next_oid = new NetSNMP::OID($base_oid . &amp;#039;.1.1&amp;#039;);&lt;br /&gt;
                                $type_oid = $oid_type{$next_oid};&lt;br /&gt;
                                $value_oid = $oid_value{$next_oid};&lt;br /&gt;
                                $request-&amp;gt;setOID($next_oid); &lt;br /&gt;
                                $request-&amp;gt;setValue($type_oid, $value_oid); &lt;br /&gt;
                        }else{&lt;br /&gt;
                                print STDERR &amp;quot;Hit by a truck whilst walking ...\n&amp;quot; if ($debugging);&lt;br /&gt;
                        }&lt;br /&gt;
                } &lt;br /&gt;
        } &lt;br /&gt;
} &lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
        if (!$agent) {&lt;br /&gt;
               help(&amp;#039;No $agent defined&amp;#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        print STDERR &amp;quot;$0 @ $regat using $mibdata ($delimV) ($delimT)\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        my $regoid = new NetSNMP::OID($regat); &lt;br /&gt;
&lt;br /&gt;
        $agent-&amp;gt;register($program, $regoid, \&amp;amp;my_snmp_handler);&lt;br /&gt;
}&lt;br /&gt;
########################################################################&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Well, the example is just an example: reading a big file in every time isn&amp;#039;t the best way ...&lt;br /&gt;
&lt;br /&gt;
Funny ideas:&lt;br /&gt;
* Use set to trigger a read &lt;br /&gt;
* The data is already formatted as a hash in a file&lt;br /&gt;
* Find another way ...&lt;br /&gt;
&lt;br /&gt;
= Conclusion =&lt;br /&gt;
A bit premature, as I&amp;#039;m not really finished yet but ...&lt;br /&gt;
&lt;br /&gt;
Using embeded perl agents from snmpd.conf may not be a good idea: note, I wrote plural of agent&amp;lt;br&amp;gt;&lt;br /&gt;
If one has only one agent in snmpd.conf, there won&amp;#039;t be to many side effects as in the @ARG section.&lt;br /&gt;
&lt;br /&gt;
It hasn&amp;#039;t been a total waste of time: brushed up some very rusty perl and maybe found out how to snmpwalk correctly which I can allways reuse in &amp;quot;the next step&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The next step for me is get a perl agent up and running that is not started from snmpd.conf and analyze that.[[User:Oxo|Oxo]] 13:18, 27 September 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;And remember&amp;#039;&amp;#039;&amp;#039;, use the extending of snmpd to allow other snmp programs access to intresting information instead of using, for example, txt files or SQL DB&amp;#039;s that are normally used to lock the information in: http://openfacts.berlios.de/index-en.phtml?title=odp&lt;br /&gt;
&lt;br /&gt;
Good luck!&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=Talk:TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3742</id>
		<title>Talk:TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=Talk:TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3742"/>
				<updated>2009-03-03T21:45:11Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: Why is loading an object multiple times a problem?&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;How is loading the shared object multiple times problematic? As long as non-static symbols of the are not exported by default, both objects should live in their private little happy place. Actually, I doubt that setting &amp;lt;code&amp;gt;RTLD_GLOBAL&amp;lt;/code&amp;gt; or similar would be a problem, because actually not symbol resolution takes place.. octo 21:45, 3 March 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3740</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3740"/>
				<updated>2009-03-03T21:35:58Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: Added section &amp;quot;See also&amp;quot;.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to build extension for Net-SNMP as &amp;lt;em&amp;gt;shared objects&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;at runtime&amp;lt;/em&amp;gt;. This adds the flexibility to add new functionality&amp;amp;nbsp;/ MIBs &amp;lt;em&amp;gt;after&amp;lt;/em&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Yet another possibility is offered by &amp;lt;em&amp;gt;Subagents&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;interprocess communication&amp;lt;/em&amp;gt; (IPC) to communicate with the daemon.&lt;br /&gt;
&lt;br /&gt;
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.&amp;amp;nbsp;e. potentially with unnecessary privileges ­— or too little, depending on your setup.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
While not strictly necessary, you&amp;#039;ll probably have an easier time building a shared object if you start with an already functioning &amp;lt;em&amp;gt;MIB module&amp;lt;/em&amp;gt; (extension) as described in [[TUT:Writing a MIB Module|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.&lt;br /&gt;
&lt;br /&gt;
For demonstration purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; The &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; code is based on the &amp;lt;code&amp;gt;UCD-DLMOD-MIB&amp;lt;/code&amp;gt;. It resides in the &amp;lt;code&amp;gt;ucdExperimental&amp;lt;/code&amp;gt; name-space, but since nothing has changed since 1999 it&amp;#039;s pretty safe to assume this interface is stable. You can find the MIB in &amp;lt;code&amp;gt;mibs/UCD-DLMOD-MIB.txt&amp;lt;/code&amp;gt; in the source-code distribution.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --with-mib-modules=&amp;quot;ucd_snmp $OTHER_MIBS&amp;quot; $OTHER_OPTIONS&lt;br /&gt;
&lt;br /&gt;
Besides the right MIB, you need of course support for shared objects. This is enabled with the &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; argument of &amp;lt;code&amp;gt;configure&amp;lt;/code&amp;gt;, 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 &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
After loading the shared object to memory, the &amp;lt;em&amp;gt;object loader&amp;lt;/em&amp;gt; will look for an initialization function inside the shared object. The name of this function is &amp;lt;code&amp;gt;init_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, where &amp;quot;name&amp;quot; is the name of your extension. The name of the example module is &amp;quot;nstAgentPluginObject&amp;quot;, so the loader will look for a function with the following prototype:&lt;br /&gt;
&lt;br /&gt;
 void init_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s a complementary function, called &amp;lt;code&amp;gt;deinit_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, 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:&lt;br /&gt;
&lt;br /&gt;
 void deinit_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
These are the only two functions called by the object loaded. All other functions (and module-global variables) therefore should be declared &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can check the names of currently loaded modules using the &amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt; OID.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
As mentioned in the introduction, you can register own configuration options which extend the daemon&amp;#039;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 &amp;lt;em&amp;gt;foobar&amp;lt;/em&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
 static const char *global_foobar = NULL;&lt;br /&gt;
 …&lt;br /&gt;
 static void config_handle (const char *key, char *value)&lt;br /&gt;
 {&lt;br /&gt;
   if (strcasecmp (&amp;quot;foobar&amp;quot;, key) == 0)&lt;br /&gt;
   {&lt;br /&gt;
     char *tmp = strdup (value);&lt;br /&gt;
     if (tmp != NULL)&lt;br /&gt;
     {&lt;br /&gt;
       free (global_foobar);&lt;br /&gt;
       global_foobar = tmp;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
   else if …&lt;br /&gt;
 } /* void config_handle */&lt;br /&gt;
 &lt;br /&gt;
 static void config_free (void)&lt;br /&gt;
 {&lt;br /&gt;
   free (global_foobar);&lt;br /&gt;
   global_foobar = NULL;&lt;br /&gt;
 }&lt;br /&gt;
 …&lt;br /&gt;
 snmpd_register_config_handler (&amp;quot;foobar&amp;quot;,&lt;br /&gt;
     config_handle, config_free,&lt;br /&gt;
     &amp;quot;The foobar option does something incredible!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Do &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; just assign the &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; pointer to a global variable or dreadful things may happen!&lt;br /&gt;
&lt;br /&gt;
== Writing the module ==&lt;br /&gt;
&lt;br /&gt;
The next steps are basically the same as those steps outlined in [[TUT:Writing a MIB Module|Writing a MIB Module]], i.&amp;amp;nbsp;e. register one or more data sets at some OIDs, for example using the [http://www.net-snmp.org/dev/agent/group__table__dataset.html#ga14 netsnmp_register_table_data_set], see [http://www.net-snmp.org/dev/agent/data__set_8c-example.html the data_set.c example]. Please see [[TUT:Writing a MIB Module|the introductory documentation]].&lt;br /&gt;
&lt;br /&gt;
== Compiling and linking the shared object ==&lt;br /&gt;
&lt;br /&gt;
Building shared objects for Net-SNMP works just like building any other shared object. If you have not done that so far, you should probably read your compilers documentation on the subject. When using the &amp;lt;em&amp;gt;GNU Compiler Collection&amp;lt;/em&amp;gt; (GCC), you will most likely need the &amp;lt;code&amp;gt;-fPIC -shared&amp;lt;/code&amp;gt; flags.&lt;br /&gt;
&lt;br /&gt;
You should use the &amp;lt;code&amp;gt;net-snmp-config&amp;lt;/code&amp;gt; script to determine additional compiler and linker flags. For example:&lt;br /&gt;
&lt;br /&gt;
 $ cc `net-snmp-config --cflags` -fPIC -shared -g -O0 -o nstAgentPluginObject.so nstAgentPluginObject.c `net-snmp-config --libs`&lt;br /&gt;
&lt;br /&gt;
You can find example &amp;lt;em&amp;gt;Makefiles&amp;lt;/em&amp;gt; at &amp;lt;code&amp;gt;agent/mibgroup/examples/Makefile.dlmod&amp;lt;/code&amp;gt; in the source-code distribution and at [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile]. Hopefully this&amp;#039;ll get you started.&lt;br /&gt;
&lt;br /&gt;
== Steps to test the shared object via runtime MIB configuration ==&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
== Loading via the snmpd.conf file ==&lt;br /&gt;
&lt;br /&gt;
A more common method of loading the shared object is to instruct the agent to load the extension at startup in the &amp;lt;code&amp;gt;snmpd.conf&amp;lt;/code&amp;gt; configuration file. This can be achieved using the &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; configuration option:&lt;br /&gt;
&lt;br /&gt;
 dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
&lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name, the second argument specifies the full pathname of the shared object file. The module name used here &amp;lt;em&amp;gt;must&amp;lt;/em&amp;gt; match the name of the initialization function, see [[#Initialization]].&lt;br /&gt;
&lt;br /&gt;
All custom configuration options, as described in [[#Configuration]], must &amp;lt;em&amp;gt;succeed&amp;lt;/em&amp;gt; the &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; statement.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[TUT:Writing a MIB Module]]&lt;br /&gt;
* [[Net-snmp extensions]]&amp;lt;br /&amp;gt;List of extensions, some of which are built as dynamically loaded objects.&lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3739</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3739"/>
				<updated>2009-03-03T21:32:45Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: /* Compiling and linking the shared object */ Rewrote the section to describe what *really* needs to be done.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to build extension for Net-SNMP as &amp;lt;em&amp;gt;shared objects&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;at runtime&amp;lt;/em&amp;gt;. This adds the flexibility to add new functionality&amp;amp;nbsp;/ MIBs &amp;lt;em&amp;gt;after&amp;lt;/em&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Yet another possibility is offered by &amp;lt;em&amp;gt;Subagents&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;interprocess communication&amp;lt;/em&amp;gt; (IPC) to communicate with the daemon.&lt;br /&gt;
&lt;br /&gt;
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.&amp;amp;nbsp;e. potentially with unnecessary privileges ­— or too little, depending on your setup.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
While not strictly necessary, you&amp;#039;ll probably have an easier time building a shared object if you start with an already functioning &amp;lt;em&amp;gt;MIB module&amp;lt;/em&amp;gt; (extension) as described in [[TUT:Writing a MIB Module|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.&lt;br /&gt;
&lt;br /&gt;
For demonstration purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; The &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; code is based on the &amp;lt;code&amp;gt;UCD-DLMOD-MIB&amp;lt;/code&amp;gt;. It resides in the &amp;lt;code&amp;gt;ucdExperimental&amp;lt;/code&amp;gt; name-space, but since nothing has changed since 1999 it&amp;#039;s pretty safe to assume this interface is stable. You can find the MIB in &amp;lt;code&amp;gt;mibs/UCD-DLMOD-MIB.txt&amp;lt;/code&amp;gt; in the source-code distribution.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --with-mib-modules=&amp;quot;ucd_snmp $OTHER_MIBS&amp;quot; $OTHER_OPTIONS&lt;br /&gt;
&lt;br /&gt;
Besides the right MIB, you need of course support for shared objects. This is enabled with the &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; argument of &amp;lt;code&amp;gt;configure&amp;lt;/code&amp;gt;, 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 &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
After loading the shared object to memory, the &amp;lt;em&amp;gt;object loader&amp;lt;/em&amp;gt; will look for an initialization function inside the shared object. The name of this function is &amp;lt;code&amp;gt;init_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, where &amp;quot;name&amp;quot; is the name of your extension. The name of the example module is &amp;quot;nstAgentPluginObject&amp;quot;, so the loader will look for a function with the following prototype:&lt;br /&gt;
&lt;br /&gt;
 void init_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s a complementary function, called &amp;lt;code&amp;gt;deinit_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, 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:&lt;br /&gt;
&lt;br /&gt;
 void deinit_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
These are the only two functions called by the object loaded. All other functions (and module-global variables) therefore should be declared &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can check the names of currently loaded modules using the &amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt; OID.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
As mentioned in the introduction, you can register own configuration options which extend the daemon&amp;#039;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 &amp;lt;em&amp;gt;foobar&amp;lt;/em&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
 static const char *global_foobar = NULL;&lt;br /&gt;
 …&lt;br /&gt;
 static void config_handle (const char *key, char *value)&lt;br /&gt;
 {&lt;br /&gt;
   if (strcasecmp (&amp;quot;foobar&amp;quot;, key) == 0)&lt;br /&gt;
   {&lt;br /&gt;
     char *tmp = strdup (value);&lt;br /&gt;
     if (tmp != NULL)&lt;br /&gt;
     {&lt;br /&gt;
       free (global_foobar);&lt;br /&gt;
       global_foobar = tmp;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
   else if …&lt;br /&gt;
 } /* void config_handle */&lt;br /&gt;
 &lt;br /&gt;
 static void config_free (void)&lt;br /&gt;
 {&lt;br /&gt;
   free (global_foobar);&lt;br /&gt;
   global_foobar = NULL;&lt;br /&gt;
 }&lt;br /&gt;
 …&lt;br /&gt;
 snmpd_register_config_handler (&amp;quot;foobar&amp;quot;,&lt;br /&gt;
     config_handle, config_free,&lt;br /&gt;
     &amp;quot;The foobar option does something incredible!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Do &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; just assign the &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; pointer to a global variable or dreadful things may happen!&lt;br /&gt;
&lt;br /&gt;
== Writing the module ==&lt;br /&gt;
&lt;br /&gt;
The next steps are basically the same as those steps outlined in [[TUT:Writing a MIB Module|Writing a MIB Module]], i.&amp;amp;nbsp;e. register one or more data sets at some OIDs, for example using the [http://www.net-snmp.org/dev/agent/group__table__dataset.html#ga14 netsnmp_register_table_data_set], see [http://www.net-snmp.org/dev/agent/data__set_8c-example.html the data_set.c example]. Please see [[TUT:Writing a MIB Module|the introductory documentation]].&lt;br /&gt;
&lt;br /&gt;
== Compiling and linking the shared object ==&lt;br /&gt;
&lt;br /&gt;
Building shared objects for Net-SNMP works just like building any other shared object. If you have not done that so far, you should probably read your compilers documentation on the subject. When using the &amp;lt;em&amp;gt;GNU Compiler Collection&amp;lt;/em&amp;gt; (GCC), you will most likely need the &amp;lt;code&amp;gt;-fPIC -shared&amp;lt;/code&amp;gt; flags.&lt;br /&gt;
&lt;br /&gt;
You should use the &amp;lt;code&amp;gt;net-snmp-config&amp;lt;/code&amp;gt; script to determine additional compiler and linker flags. For example:&lt;br /&gt;
&lt;br /&gt;
 $ cc `net-snmp-config --cflags` -fPIC -shared -g -O0 -o nstAgentPluginObject.so nstAgentPluginObject.c `net-snmp-config --libs`&lt;br /&gt;
&lt;br /&gt;
You can find example &amp;lt;em&amp;gt;Makefiles&amp;lt;/em&amp;gt; at &amp;lt;code&amp;gt;agent/mibgroup/examples/Makefile.dlmod&amp;lt;/code&amp;gt; in the source-code distribution and at [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile]. Hopefully this&amp;#039;ll get you started.&lt;br /&gt;
&lt;br /&gt;
== Steps to test the shared object via runtime MIB configuration ==&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
== Loading via the snmpd.conf file ==&lt;br /&gt;
&lt;br /&gt;
A more common method of loading the shared object is to instruct the agent to load the extension at startup in the &amp;lt;code&amp;gt;snmpd.conf&amp;lt;/code&amp;gt; configuration file. This can be achieved using the &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; configuration option:&lt;br /&gt;
&lt;br /&gt;
 dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
&lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name, the second argument specifies the full pathname of the shared object file. The module name used here &amp;lt;em&amp;gt;must&amp;lt;/em&amp;gt; match the name of the initialization function, see [[#Initialization]].&lt;br /&gt;
&lt;br /&gt;
All custom configuration options, as described in [[#Configuration]], must &amp;lt;em&amp;gt;succeed&amp;lt;/em&amp;gt; the &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; statement.&lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3738</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3738"/>
				<updated>2009-03-03T21:22:59Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: /* Loading via the snmpd.conf file */ Improved the &amp;quot;Loading via the snmpd.conf file&amp;quot; section.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to build extension for Net-SNMP as &amp;lt;em&amp;gt;shared objects&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;at runtime&amp;lt;/em&amp;gt;. This adds the flexibility to add new functionality&amp;amp;nbsp;/ MIBs &amp;lt;em&amp;gt;after&amp;lt;/em&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Yet another possibility is offered by &amp;lt;em&amp;gt;Subagents&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;interprocess communication&amp;lt;/em&amp;gt; (IPC) to communicate with the daemon.&lt;br /&gt;
&lt;br /&gt;
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.&amp;amp;nbsp;e. potentially with unnecessary privileges ­— or too little, depending on your setup.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
While not strictly necessary, you&amp;#039;ll probably have an easier time building a shared object if you start with an already functioning &amp;lt;em&amp;gt;MIB module&amp;lt;/em&amp;gt; (extension) as described in [[TUT:Writing a MIB Module|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.&lt;br /&gt;
&lt;br /&gt;
For demonstration purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; The &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; code is based on the &amp;lt;code&amp;gt;UCD-DLMOD-MIB&amp;lt;/code&amp;gt;. It resides in the &amp;lt;code&amp;gt;ucdExperimental&amp;lt;/code&amp;gt; name-space, but since nothing has changed since 1999 it&amp;#039;s pretty safe to assume this interface is stable. You can find the MIB in &amp;lt;code&amp;gt;mibs/UCD-DLMOD-MIB.txt&amp;lt;/code&amp;gt; in the source-code distribution.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --with-mib-modules=&amp;quot;ucd_snmp $OTHER_MIBS&amp;quot; $OTHER_OPTIONS&lt;br /&gt;
&lt;br /&gt;
Besides the right MIB, you need of course support for shared objects. This is enabled with the &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; argument of &amp;lt;code&amp;gt;configure&amp;lt;/code&amp;gt;, 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 &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
After loading the shared object to memory, the &amp;lt;em&amp;gt;object loader&amp;lt;/em&amp;gt; will look for an initialization function inside the shared object. The name of this function is &amp;lt;code&amp;gt;init_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, where &amp;quot;name&amp;quot; is the name of your extension. The name of the example module is &amp;quot;nstAgentPluginObject&amp;quot;, so the loader will look for a function with the following prototype:&lt;br /&gt;
&lt;br /&gt;
 void init_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s a complementary function, called &amp;lt;code&amp;gt;deinit_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, 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:&lt;br /&gt;
&lt;br /&gt;
 void deinit_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
These are the only two functions called by the object loaded. All other functions (and module-global variables) therefore should be declared &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can check the names of currently loaded modules using the &amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt; OID.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
As mentioned in the introduction, you can register own configuration options which extend the daemon&amp;#039;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 &amp;lt;em&amp;gt;foobar&amp;lt;/em&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
 static const char *global_foobar = NULL;&lt;br /&gt;
 …&lt;br /&gt;
 static void config_handle (const char *key, char *value)&lt;br /&gt;
 {&lt;br /&gt;
   if (strcasecmp (&amp;quot;foobar&amp;quot;, key) == 0)&lt;br /&gt;
   {&lt;br /&gt;
     char *tmp = strdup (value);&lt;br /&gt;
     if (tmp != NULL)&lt;br /&gt;
     {&lt;br /&gt;
       free (global_foobar);&lt;br /&gt;
       global_foobar = tmp;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
   else if …&lt;br /&gt;
 } /* void config_handle */&lt;br /&gt;
 &lt;br /&gt;
 static void config_free (void)&lt;br /&gt;
 {&lt;br /&gt;
   free (global_foobar);&lt;br /&gt;
   global_foobar = NULL;&lt;br /&gt;
 }&lt;br /&gt;
 …&lt;br /&gt;
 snmpd_register_config_handler (&amp;quot;foobar&amp;quot;,&lt;br /&gt;
     config_handle, config_free,&lt;br /&gt;
     &amp;quot;The foobar option does something incredible!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Do &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; just assign the &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; pointer to a global variable or dreadful things may happen!&lt;br /&gt;
&lt;br /&gt;
== Writing the module ==&lt;br /&gt;
&lt;br /&gt;
The next steps are basically the same as those steps outlined in [[TUT:Writing a MIB Module|Writing a MIB Module]], i.&amp;amp;nbsp;e. register one or more data sets at some OIDs, for example using the [http://www.net-snmp.org/dev/agent/group__table__dataset.html#ga14 netsnmp_register_table_data_set], see [http://www.net-snmp.org/dev/agent/data__set_8c-example.html the data_set.c example]. Please see [[TUT:Writing a MIB Module|the introductory documentation]].&lt;br /&gt;
&lt;br /&gt;
== Steps to build the shared object ==&lt;br /&gt;
&lt;br /&gt;
# First off we must get the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile Makefile] file, the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] file, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] file. &lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;make nstAgentPluginObject.so&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Steps to test the shared object via runtime MIB configuration ==&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
== Loading via the snmpd.conf file ==&lt;br /&gt;
&lt;br /&gt;
A more common method of loading the shared object is to instruct the agent to load the extension at startup in the &amp;lt;code&amp;gt;snmpd.conf&amp;lt;/code&amp;gt; configuration file. This can be achieved using the &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; configuration option:&lt;br /&gt;
&lt;br /&gt;
 dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
&lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name, the second argument specifies the full pathname of the shared object file. The module name used here &amp;lt;em&amp;gt;must&amp;lt;/em&amp;gt; match the name of the initialization function, see [[#Initialization]].&lt;br /&gt;
&lt;br /&gt;
All custom configuration options, as described in [[#Configuration]], must &amp;lt;em&amp;gt;succeed&amp;lt;/em&amp;gt; the &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; statement.&lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3737</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3737"/>
				<updated>2009-03-03T21:15:13Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: /* Introduction */ Clarified the distinction between built-in and dynamically loaded MIB objects.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to build extension for Net-SNMP as &amp;lt;em&amp;gt;shared objects&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;at runtime&amp;lt;/em&amp;gt;. This adds the flexibility to add new functionality&amp;amp;nbsp;/ MIBs &amp;lt;em&amp;gt;after&amp;lt;/em&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Yet another possibility is offered by &amp;lt;em&amp;gt;Subagents&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;interprocess communication&amp;lt;/em&amp;gt; (IPC) to communicate with the daemon.&lt;br /&gt;
&lt;br /&gt;
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.&amp;amp;nbsp;e. potentially with unnecessary privileges ­— or too little, depending on your setup.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
While not strictly necessary, you&amp;#039;ll probably have an easier time building a shared object if you start with an already functioning &amp;lt;em&amp;gt;MIB module&amp;lt;/em&amp;gt; (extension) as described in [[TUT:Writing a MIB Module|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.&lt;br /&gt;
&lt;br /&gt;
For demonstration purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; The &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; code is based on the &amp;lt;code&amp;gt;UCD-DLMOD-MIB&amp;lt;/code&amp;gt;. It resides in the &amp;lt;code&amp;gt;ucdExperimental&amp;lt;/code&amp;gt; name-space, but since nothing has changed since 1999 it&amp;#039;s pretty safe to assume this interface is stable. You can find the MIB in &amp;lt;code&amp;gt;mibs/UCD-DLMOD-MIB.txt&amp;lt;/code&amp;gt; in the source-code distribution.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --with-mib-modules=&amp;quot;ucd_snmp $OTHER_MIBS&amp;quot; $OTHER_OPTIONS&lt;br /&gt;
&lt;br /&gt;
Besides the right MIB, you need of course support for shared objects. This is enabled with the &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; argument of &amp;lt;code&amp;gt;configure&amp;lt;/code&amp;gt;, 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 &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
After loading the shared object to memory, the &amp;lt;em&amp;gt;object loader&amp;lt;/em&amp;gt; will look for an initialization function inside the shared object. The name of this function is &amp;lt;code&amp;gt;init_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, where &amp;quot;name&amp;quot; is the name of your extension. The name of the example module is &amp;quot;nstAgentPluginObject&amp;quot;, so the loader will look for a function with the following prototype:&lt;br /&gt;
&lt;br /&gt;
 void init_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s a complementary function, called &amp;lt;code&amp;gt;deinit_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, 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:&lt;br /&gt;
&lt;br /&gt;
 void deinit_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
These are the only two functions called by the object loaded. All other functions (and module-global variables) therefore should be declared &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can check the names of currently loaded modules using the &amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt; OID.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
As mentioned in the introduction, you can register own configuration options which extend the daemon&amp;#039;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 &amp;lt;em&amp;gt;foobar&amp;lt;/em&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
 static const char *global_foobar = NULL;&lt;br /&gt;
 …&lt;br /&gt;
 static void config_handle (const char *key, char *value)&lt;br /&gt;
 {&lt;br /&gt;
   if (strcasecmp (&amp;quot;foobar&amp;quot;, key) == 0)&lt;br /&gt;
   {&lt;br /&gt;
     char *tmp = strdup (value);&lt;br /&gt;
     if (tmp != NULL)&lt;br /&gt;
     {&lt;br /&gt;
       free (global_foobar);&lt;br /&gt;
       global_foobar = tmp;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
   else if …&lt;br /&gt;
 } /* void config_handle */&lt;br /&gt;
 &lt;br /&gt;
 static void config_free (void)&lt;br /&gt;
 {&lt;br /&gt;
   free (global_foobar);&lt;br /&gt;
   global_foobar = NULL;&lt;br /&gt;
 }&lt;br /&gt;
 …&lt;br /&gt;
 snmpd_register_config_handler (&amp;quot;foobar&amp;quot;,&lt;br /&gt;
     config_handle, config_free,&lt;br /&gt;
     &amp;quot;The foobar option does something incredible!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Do &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; just assign the &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; pointer to a global variable or dreadful things may happen!&lt;br /&gt;
&lt;br /&gt;
== Writing the module ==&lt;br /&gt;
&lt;br /&gt;
The next steps are basically the same as those steps outlined in [[TUT:Writing a MIB Module|Writing a MIB Module]], i.&amp;amp;nbsp;e. register one or more data sets at some OIDs, for example using the [http://www.net-snmp.org/dev/agent/group__table__dataset.html#ga14 netsnmp_register_table_data_set], see [http://www.net-snmp.org/dev/agent/data__set_8c-example.html the data_set.c example]. Please see [[TUT:Writing a MIB Module|the introductory documentation]].&lt;br /&gt;
&lt;br /&gt;
== Steps to build the shared object ==&lt;br /&gt;
&lt;br /&gt;
# First off we must get the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile Makefile] file, the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] file, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] file. &lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;make nstAgentPluginObject.so&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Steps to test the shared object via runtime MIB configuration ==&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
== Loading via the snmpd.conf file ==&lt;br /&gt;
You can also load shared objects using the &amp;quot;dlmod&amp;quot; token in the snmpd.conf file by putting a line like this in your snmpd.conf file: &lt;br /&gt;
      dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
    &lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name (UCD-DLMOD-MIB::dlmodName) and second argument specifies the full pathname of the shared object file. &lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3736</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3736"/>
				<updated>2009-03-03T21:05:15Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: /* Prerequisites */ Rephrased much of the section.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to build extension for Net-SNMP as &amp;lt;em&amp;gt;shared objects&amp;lt;/em&amp;gt;, binary files that can be loaded by the SNMPd daemon directly and are executed as part of the daemon. This differs from the concept of &amp;lt;em&amp;gt;Subagents&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;interprocess communication&amp;lt;/em&amp;gt; (IPC) to communicate with the daemon.&lt;br /&gt;
&lt;br /&gt;
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.&amp;amp;nbsp;e. potentially with unnecessary privileges ­— or too little, depending on your setup.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
While not strictly necessary, you&amp;#039;ll probably have an easier time building a shared object if you start with an already functioning &amp;lt;em&amp;gt;MIB module&amp;lt;/em&amp;gt; (extension) as described in [[TUT:Writing a MIB Module|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.&lt;br /&gt;
&lt;br /&gt;
For demonstration purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; The &amp;lt;code&amp;gt;dlmod&amp;lt;/code&amp;gt; code is based on the &amp;lt;code&amp;gt;UCD-DLMOD-MIB&amp;lt;/code&amp;gt;. It resides in the &amp;lt;code&amp;gt;ucdExperimental&amp;lt;/code&amp;gt; name-space, but since nothing has changed since 1999 it&amp;#039;s pretty safe to assume this interface is stable. You can find the MIB in &amp;lt;code&amp;gt;mibs/UCD-DLMOD-MIB.txt&amp;lt;/code&amp;gt; in the source-code distribution.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --with-mib-modules=&amp;quot;ucd_snmp $OTHER_MIBS&amp;quot; $OTHER_OPTIONS&lt;br /&gt;
&lt;br /&gt;
Besides the right MIB, you need of course support for shared objects. This is enabled with the &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; argument of &amp;lt;code&amp;gt;configure&amp;lt;/code&amp;gt;, 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 &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
After loading the shared object to memory, the &amp;lt;em&amp;gt;object loader&amp;lt;/em&amp;gt; will look for an initialization function inside the shared object. The name of this function is &amp;lt;code&amp;gt;init_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, where &amp;quot;name&amp;quot; is the name of your extension. The name of the example module is &amp;quot;nstAgentPluginObject&amp;quot;, so the loader will look for a function with the following prototype:&lt;br /&gt;
&lt;br /&gt;
 void init_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s a complementary function, called &amp;lt;code&amp;gt;deinit_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, 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:&lt;br /&gt;
&lt;br /&gt;
 void deinit_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
These are the only two functions called by the object loaded. All other functions (and module-global variables) therefore should be declared &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can check the names of currently loaded modules using the &amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt; OID.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
As mentioned in the introduction, you can register own configuration options which extend the daemon&amp;#039;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 &amp;lt;em&amp;gt;foobar&amp;lt;/em&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
 static const char *global_foobar = NULL;&lt;br /&gt;
 …&lt;br /&gt;
 static void config_handle (const char *key, char *value)&lt;br /&gt;
 {&lt;br /&gt;
   if (strcasecmp (&amp;quot;foobar&amp;quot;, key) == 0)&lt;br /&gt;
   {&lt;br /&gt;
     char *tmp = strdup (value);&lt;br /&gt;
     if (tmp != NULL)&lt;br /&gt;
     {&lt;br /&gt;
       free (global_foobar);&lt;br /&gt;
       global_foobar = tmp;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
   else if …&lt;br /&gt;
 } /* void config_handle */&lt;br /&gt;
 &lt;br /&gt;
 static void config_free (void)&lt;br /&gt;
 {&lt;br /&gt;
   free (global_foobar);&lt;br /&gt;
   global_foobar = NULL;&lt;br /&gt;
 }&lt;br /&gt;
 …&lt;br /&gt;
 snmpd_register_config_handler (&amp;quot;foobar&amp;quot;,&lt;br /&gt;
     config_handle, config_free,&lt;br /&gt;
     &amp;quot;The foobar option does something incredible!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Do &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; just assign the &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; pointer to a global variable or dreadful things may happen!&lt;br /&gt;
&lt;br /&gt;
== Writing the module ==&lt;br /&gt;
&lt;br /&gt;
The next steps are basically the same as those steps outlined in [[TUT:Writing a MIB Module|Writing a MIB Module]], i.&amp;amp;nbsp;e. register one or more data sets at some OIDs, for example using the [http://www.net-snmp.org/dev/agent/group__table__dataset.html#ga14 netsnmp_register_table_data_set], see [http://www.net-snmp.org/dev/agent/data__set_8c-example.html the data_set.c example]. Please see [[TUT:Writing a MIB Module|the introductory documentation]].&lt;br /&gt;
&lt;br /&gt;
== Steps to build the shared object ==&lt;br /&gt;
&lt;br /&gt;
# First off we must get the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile Makefile] file, the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] file, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] file. &lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;make nstAgentPluginObject.so&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Steps to test the shared object via runtime MIB configuration ==&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
== Loading via the snmpd.conf file ==&lt;br /&gt;
You can also load shared objects using the &amp;quot;dlmod&amp;quot; token in the snmpd.conf file by putting a line like this in your snmpd.conf file: &lt;br /&gt;
      dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
    &lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name (UCD-DLMOD-MIB::dlmodName) and second argument specifies the full pathname of the shared object file. &lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3735</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3735"/>
				<updated>2009-03-03T20:38:05Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: Added section &amp;quot;Configuration&amp;quot;.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to build extension for Net-SNMP as &amp;lt;em&amp;gt;shared objects&amp;lt;/em&amp;gt;, binary files that can be loaded by the SNMPd daemon directly and are executed as part of the daemon. This differs from the concept of &amp;lt;em&amp;gt;Subagents&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;interprocess communication&amp;lt;/em&amp;gt; (IPC) to communicate with the daemon.&lt;br /&gt;
&lt;br /&gt;
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.&amp;amp;nbsp;e. potentially with unnecessary privileges ­— or too little, depending on your setup.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
First off, you need to write a MIB module first before you can do this part of the tutorial. We assume you have read and completed the [[TUT:Writing_a_MIB_Module | MIB module portion]] of the toolkit tutorial. This part of the tutorial shows how to install a dynamic module into the agent, assuming you already have written a MIB module which we&amp;#039;ll then compile into a dynamic module. For example purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; For this to work, you must have compiled the net-snmp package with dynamically loadable module support turned on, as well as built it with &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; turned on. (It&amp;#039;s on by default, if your system supports it). You can check for support in your agent but looking at the output of the &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
After loading the shared object to memory, the &amp;lt;em&amp;gt;object loader&amp;lt;/em&amp;gt; will look for an initialization function inside the shared object. The name of this function is &amp;lt;code&amp;gt;init_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, where &amp;quot;name&amp;quot; is the name of your extension. The name of the example module is &amp;quot;nstAgentPluginObject&amp;quot;, so the loader will look for a function with the following prototype:&lt;br /&gt;
&lt;br /&gt;
 void init_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s a complementary function, called &amp;lt;code&amp;gt;deinit_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, 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:&lt;br /&gt;
&lt;br /&gt;
 void deinit_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
These are the only two functions called by the object loaded. All other functions (and module-global variables) therefore should be declared &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can check the names of currently loaded modules using the &amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt; OID.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
As mentioned in the introduction, you can register own configuration options which extend the daemon&amp;#039;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 &amp;lt;em&amp;gt;foobar&amp;lt;/em&amp;gt; option:&lt;br /&gt;
&lt;br /&gt;
 static const char *global_foobar = NULL;&lt;br /&gt;
 …&lt;br /&gt;
 static void config_handle (const char *key, char *value)&lt;br /&gt;
 {&lt;br /&gt;
   if (strcasecmp (&amp;quot;foobar&amp;quot;, key) == 0)&lt;br /&gt;
   {&lt;br /&gt;
     char *tmp = strdup (value);&lt;br /&gt;
     if (tmp != NULL)&lt;br /&gt;
     {&lt;br /&gt;
       free (global_foobar);&lt;br /&gt;
       global_foobar = tmp;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
   else if …&lt;br /&gt;
 } /* void config_handle */&lt;br /&gt;
 &lt;br /&gt;
 static void config_free (void)&lt;br /&gt;
 {&lt;br /&gt;
   free (global_foobar);&lt;br /&gt;
   global_foobar = NULL;&lt;br /&gt;
 }&lt;br /&gt;
 …&lt;br /&gt;
 snmpd_register_config_handler (&amp;quot;foobar&amp;quot;,&lt;br /&gt;
     config_handle, config_free,&lt;br /&gt;
     &amp;quot;The foobar option does something incredible!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Do &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; just assign the &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; pointer to a global variable or dreadful things may happen!&lt;br /&gt;
&lt;br /&gt;
== Writing the module ==&lt;br /&gt;
&lt;br /&gt;
The next steps are basically the same as those steps outlined in [[TUT:Writing a MIB Module|Writing a MIB Module]], i.&amp;amp;nbsp;e. register one or more data sets at some OIDs, for example using the [http://www.net-snmp.org/dev/agent/group__table__dataset.html#ga14 netsnmp_register_table_data_set], see [http://www.net-snmp.org/dev/agent/data__set_8c-example.html the data_set.c example]. Please see [[TUT:Writing a MIB Module|the introductory documentation]].&lt;br /&gt;
&lt;br /&gt;
== Steps to build the shared object ==&lt;br /&gt;
&lt;br /&gt;
# First off we must get the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile Makefile] file, the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] file, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] file. &lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;make nstAgentPluginObject.so&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Steps to test the shared object via runtime MIB configuration ==&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
== Loading via the snmpd.conf file ==&lt;br /&gt;
You can also load shared objects using the &amp;quot;dlmod&amp;quot; token in the snmpd.conf file by putting a line like this in your snmpd.conf file: &lt;br /&gt;
      dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
    &lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name (UCD-DLMOD-MIB::dlmodName) and second argument specifies the full pathname of the shared object file. &lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3734</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3734"/>
				<updated>2009-03-03T20:11:15Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: Added section &amp;quot;Initialization&amp;quot;.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to build extension for Net-SNMP as &amp;lt;em&amp;gt;shared objects&amp;lt;/em&amp;gt;, binary files that can be loaded by the SNMPd daemon directly and are executed as part of the daemon. This differs from the concept of &amp;lt;em&amp;gt;Subagents&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;interprocess communication&amp;lt;/em&amp;gt; (IPC) to communicate with the daemon.&lt;br /&gt;
&lt;br /&gt;
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.&amp;amp;nbsp;e. potentially with unnecessary privileges ­— or too little, depending on your setup.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
First off, you need to write a MIB module first before you can do this part of the tutorial. We assume you have read and completed the [[TUT:Writing_a_MIB_Module | MIB module portion]] of the toolkit tutorial. This part of the tutorial shows how to install a dynamic module into the agent, assuming you already have written a MIB module which we&amp;#039;ll then compile into a dynamic module. For example purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; For this to work, you must have compiled the net-snmp package with dynamically loadable module support turned on, as well as built it with &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; turned on. (It&amp;#039;s on by default, if your system supports it). You can check for support in your agent but looking at the output of the &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
After loading the shared object to memory, the &amp;lt;em&amp;gt;object loader&amp;lt;/em&amp;gt; will look for an initialization function inside the shared object. The name of this function is &amp;lt;code&amp;gt;init_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, where &amp;quot;name&amp;quot; is the name of your extension. The name of the example module is &amp;quot;nstAgentPluginObject&amp;quot;, so the loader will look for a function with the following prototype:&lt;br /&gt;
&lt;br /&gt;
 void init_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
There&amp;#039;s a complementary function, called &amp;lt;code&amp;gt;deinit_&amp;lt;em&amp;gt;name&amp;lt;/em&amp;gt;&amp;lt;/code&amp;gt;, 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:&lt;br /&gt;
&lt;br /&gt;
 void deinit_nstAgentPluginObject (void);&lt;br /&gt;
&lt;br /&gt;
These are the only two functions called by the object loaded. All other functions (and module-global variables) therefore should be declared &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can check the names of currently loaded modules using the &amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt; OID.&lt;br /&gt;
&lt;br /&gt;
== Steps to build the shared object ==&lt;br /&gt;
&lt;br /&gt;
# First off we must get the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile Makefile] file, the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] file, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] file. &lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;make nstAgentPluginObject.so&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Steps to test the shared object via runtime MIB configuration ==&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
== Loading via the snmpd.conf file ==&lt;br /&gt;
You can also load shared objects using the &amp;quot;dlmod&amp;quot; token in the snmpd.conf file by putting a line like this in your snmpd.conf file: &lt;br /&gt;
      dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
    &lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name (UCD-DLMOD-MIB::dlmodName) and second argument specifies the full pathname of the shared object file. &lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3733</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3733"/>
				<updated>2009-03-03T20:00:50Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: Wrote an introduction to the tutorial, so the user knows what&amp;#039;s expecting her.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to build extension for Net-SNMP as &amp;lt;em&amp;gt;shared objects&amp;lt;/em&amp;gt;, binary files that can be loaded by the SNMPd daemon directly and are executed as part of the daemon. This differs from the concept of &amp;lt;em&amp;gt;Subagents&amp;lt;/em&amp;gt;, 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 &amp;lt;em&amp;gt;interprocess communication&amp;lt;/em&amp;gt; (IPC) to communicate with the daemon.&lt;br /&gt;
&lt;br /&gt;
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.&amp;amp;nbsp;e. potentially with unnecessary privileges ­— or too little, depending on your setup.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
First off, you need to write a MIB module first before you can do this part of the tutorial. We assume you have read and completed the [[TUT:Writing_a_MIB_Module | MIB module portion]] of the toolkit tutorial. This part of the tutorial shows how to install a dynamic module into the agent, assuming you already have written a MIB module which we&amp;#039;ll then compile into a dynamic module. For example purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; For this to work, you must have compiled the net-snmp package with dynamically loadable module support turned on, as well as built it with &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; turned on. (It&amp;#039;s on by default, if your system supports it). You can check for support in your agent but looking at the output of the &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The shared object loader calls the &amp;quot;&amp;lt;code&amp;gt;init_nstAgentPluginObject()&amp;lt;/code&amp;gt;&amp;quot; function in the above code when it gets loaded, and calls the &amp;quot;&amp;lt;code&amp;gt;deinit_nstAgentPluginObject()&amp;lt;/code&amp;gt;&amp;quot; when (and if) the module is unloaded. These function names to use are built by adding the shared object&amp;#039;s module name (&amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt;) to the &amp;quot;&amp;lt;code&amp;gt;init_&amp;lt;/code&amp;gt;&amp;quot; and &amp;quot;&amp;lt;code&amp;gt;deinit_&amp;lt;/code&amp;gt;&amp;quot; prefixes. &lt;br /&gt;
&lt;br /&gt;
== Steps to build the shared object ==&lt;br /&gt;
&lt;br /&gt;
# First off we must get the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile Makefile] file, the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] file, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] file. &lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;make nstAgentPluginObject.so&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Steps to test the shared object via runtime MIB configuration ==&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
== Loading via the snmpd.conf file ==&lt;br /&gt;
You can also load shared objects using the &amp;quot;dlmod&amp;quot; token in the snmpd.conf file by putting a line like this in your snmpd.conf file: &lt;br /&gt;
      dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
    &lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name (UCD-DLMOD-MIB::dlmodName) and second argument specifies the full pathname of the shared object file. &lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	<entry>
		<id>https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3732</id>
		<title>TUT:Writing a Dynamically Loadable Object</title>
		<link rel="alternate" type="text/html" href="https://net-snmp.sourceforge.io/wiki/index.php?title=TUT:Writing_a_Dynamically_Loadable_Object&amp;diff=3732"/>
				<updated>2009-03-03T19:44:50Z</updated>
		
		<summary type="html">&lt;p&gt;Octo: Improve markup in the introduction.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;First off, you need to write a MIB module first before you can do this part of the tutorial. We assume you have read and completed the [[TUT:Writing_a_MIB_Module | MIB module portion]] of the toolkit tutorial. This part of the tutorial shows how to install a dynamic module into the agent, assuming you already have written a MIB module which we&amp;#039;ll then compile into a dynamic module. For example purposes, we&amp;#039;ll refer to some example MIB objects and code: the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mib_module/NET-SNMP-TUTORIAL-MIB.txt NET-SNMP-TUTORIAL-MIB] MIB, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.c example MIB module] and it&amp;#039;s [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/nstAgentSubagentObject.h header file]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; For this to work, you must have compiled the net-snmp package with dynamically loadable module support turned on, as well as built it with &amp;lt;code&amp;gt;--enable-shared&amp;lt;/code&amp;gt; turned on. (It&amp;#039;s on by default, if your system supports it). You can check for support in your agent but looking at the output of the &amp;lt;code&amp;gt;snmpd&amp;amp;nbsp;-H&amp;lt;/code&amp;gt; command for the &amp;quot;dlmod&amp;quot; token. If its listed, the compiled agent supports it. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; All command line options below assume you have an appropriately setup &amp;lt;code&amp;gt;~/.snmp/snmp.conf&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;/usr/local/share/snmp/snmpd.conf&amp;lt;/code&amp;gt; file (or equivalent). &lt;br /&gt;
&lt;br /&gt;
{{TUT:File-Table-Top-and-basics}}&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] || The MIB module&amp;#039;s header file&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] || The MIB module&amp;#039;s C source code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The shared object loader calls the &amp;quot;&amp;lt;code&amp;gt;init_nstAgentPluginObject()&amp;lt;/code&amp;gt;&amp;quot; function in the above code when it gets loaded, and calls the &amp;quot;&amp;lt;code&amp;gt;deinit_nstAgentPluginObject()&amp;lt;/code&amp;gt;&amp;quot; when (and if) the module is unloaded. These function names to use are built by adding the shared object&amp;#039;s module name (&amp;lt;code&amp;gt;UCD-DLMOD-MIB::dlmodName&amp;lt;/code&amp;gt;) to the &amp;quot;&amp;lt;code&amp;gt;init_&amp;lt;/code&amp;gt;&amp;quot; and &amp;quot;&amp;lt;code&amp;gt;deinit_&amp;lt;/code&amp;gt;&amp;quot; prefixes. &lt;br /&gt;
&lt;br /&gt;
=== Steps to build the shared object ===&lt;br /&gt;
&lt;br /&gt;
# First off we must get the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demoapp/Makefile Makefile] file, the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.h nstAgentPluginObject.h] file, and the [http://www.net-snmp.org/tutorial/tutorial-5/toolkit/dlmod/nstAgentPluginObject.c nstAgentPluginObject.c] file. &lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;make nstAgentPluginObject.so&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== Steps to test the shared object via runtime MIB configuration ===&lt;br /&gt;
&lt;br /&gt;
# 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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpd -f -L -DnstAgentPluginObject,dlmod&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
# In another window, test to make sure that the agent doesn&amp;#039;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): &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:nstAgentPluginObject.0 = No Such Object available on this agent at this OID          &lt;br /&gt;
# Then, run snmpset to create a new row in the dlmod table: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i create&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = create(6)&lt;br /&gt;
# See that the row was created: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#:&lt;br /&gt;
#:dlmodName dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#:                                   unloaded&lt;br /&gt;
#Then set the properties of the row up to point to our new object and to give it a name: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodName.1 s &amp;quot;nstAgentPluginObject&amp;quot; UCD-DLMOD-MIB::dlmodPath.1 s &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodName.1 = &amp;quot;nstAgentPluginObject&amp;quot; &lt;br /&gt;
#:dlmodName.1 = &amp;quot;/path/to/nstAgentPluginObject.so&amp;quot;&lt;br /&gt;
#:&lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmptable localhost UCD-DLMOD-MIB::dlmodTable  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName dlmodPath                 dlmodError   dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                  unloaded&lt;br /&gt;
#Finally, load the shared object into the running agent: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpset localhost UCD-DLMOD-MIB::dlmodStatus.1 i load  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#:dlmodStatus.1 = loaded(1)&lt;br /&gt;
#:&lt;br /&gt;
#:% snmptable localhost UCD-DLMOD-MIB::dlmodTable  &lt;br /&gt;
#:SNMP table: dlmodTable&lt;br /&gt;
#: &lt;br /&gt;
#:    dlmodName                      dlmodPath dlmodError dlmodStatus&lt;br /&gt;
#: nstAgentPluginObject /path/to/nstAgentPluginObject.so                 loaded&lt;br /&gt;
#If everything above was done correctly, then the following command should work and will access the shared object&amp;#039;s data: &lt;br /&gt;
#:% &amp;#039;&amp;#039;&amp;#039;snmpget localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0  &amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#: nstAgentPluginObject.0 = INTEGER: 3&lt;br /&gt;
&lt;br /&gt;
=== Loading via the snmpd.conf file ===&lt;br /&gt;
You can also load shared objects using the &amp;quot;dlmod&amp;quot; token in the snmpd.conf file by putting a line like this in your snmpd.conf file: &lt;br /&gt;
      dlmod nstAgentPluginObject /path/to/nstAgentPluginObject.so&lt;br /&gt;
    &lt;br /&gt;
The first argument specifies the shared object&amp;#039;s module name (UCD-DLMOD-MIB::dlmodName) and second argument specifies the full pathname of the shared object file. &lt;br /&gt;
&lt;br /&gt;
{{TUT:LIST}}&lt;/div&gt;</summary>
		<author><name>Octo</name></author>	</entry>

	</feed>