1 Note, this is based on the text from a web page, which can be found in
2 the documentation section of the http://www.net-snmp.org web page.
4 Extending the UCD-SNMP agent
5 ============================
7 This document describes the procedure for writing code to extend
8 the functionality of the v4 UCD-SNMP network management agent.
9 Modules written using this procedure will also work with the v5
10 Net-SNMP agent, though this will not take advantage of the new
11 handler-based helper mechanisms. See the on-line documentation
12 for more information and examples of that mechanism.
13 We would be very interested in comment and feedback about how useful
14 useful you find this description, and ways in which it could be improved.
16 The information is designed to be read in order - the structure being:
18 1. Overview & Introduction
19 2. MIB files, and how they relate to the agent implementation
21 4. The basic structure of module implementation code
22 5. The details of non-table based implementations
23 6. The details of simple table based implementations
24 7. The details of more general table based implementations
25 8. How to implement SET-able variables
27 While the document is intended to be generally self-contained,
28 it does occasionally refer to code files shipped with the main UCD
29 distribution (in particular the example module), and it may prove
30 useful to have these files available for reference.
32 1. How to write a Mib module
33 ============================
38 The design of the UCD SNMP agent has always been shaped by the desire to be
39 able to extend its functionality by adding new modules. One of the earliest
40 developments from the underlying CMU code base was the ability to call
41 external scripts, and this is probably the simplest method of extending the
43 However, there are circumstances where such an approach is felt to be
44 inappropriate - perhaps from considerations of speed, access to the
45 necessary data, reliability or elegance. In such cases, the obvious solution
46 is to provide C code that can be compiled into the agent itself to implement
47 the desired module. Many of the more recent developments in the code
48 structure have been intended to ease this process. In particular, one of the
49 more recent additions to the suite is the tool mib2c. This is designed to
50 take a portion of the MIB tree (as defined by a MIB file) and generate the
51 code skeleton necessary to implement this. This document will cover the use
52 mib2c, as well as describing the requirements and functionality of the code
55 In order to implement a new MIB module, three files are necessary, and these
56 will be considered in turn. Note that, by the very nature of the task, this
57 document cannot cover the details of precisely how to obtain the necessary
58 information from the operating system or application. Instead, it describes
59 the code framework that is needed, freeing the implementer from needing to
60 understand the detailed internals of the agent, and allowing them to
61 concentrate on the particular problem in hand.
63 It may prove useful to examine some of the existing module implementations
64 and examples in the light of this description, and suitable examples will be
65 referred to at the appropriate points. However, it should be remembered that
66 the UCD agent seeks to support a wide variety of systems, often with
67 dramatically differing implementations and interfaces, and this is reflected
68 in the complexity of the code. Also, the agent has developed gradually over
69 the years, and there is often some measure of duplication or redundancy as a
71 As the FAQ states, the official slogan of the UCD-SNMP developers is
73 The current implementation is non-obvious and may need to be
76 This document describes the ideal, straightforward cases - real life is
77 rarely so simple, and the example modules may prove easier to follow at a
79 It is also advisable to have a compiled and installed implementation
80 available before starting to extend the agent. This will make debugging and
81 testing the agent much easier.
83 A note regarding terminology - the word "module" is widely used throughout
84 this document, with a number of different meanings.
86 * support for a new MIB,
87 i.e. the whole of the functionality that is required. This is usually
89 * a self-contained subset of this, implemented as a single unit.
90 This is usually termed an implementation module (or simply "a module");
91 * the combination of such subsets, usually termed a module group.
93 Note that the first and third of these are often synonymous - the
94 difference being that a MIB module refers to the view from outside the
95 agent, regarding this as a seamless whole and hiding the internal
96 implementation. A "module group" is used where the internal structure is of
97 more relevance, and recognises the fact that the functionality may be
98 provided by a number of co-operating implementation modules.
100 Anyway, enough waffle - on with the details: The three files needed are
102 * a MIB definition file;
104 * a C implementation file.
106 The next part looks at the MIB definition file, and how this impacts on the
107 agent implementation.
112 The first file needed is the MIB file that defines the MIB module to be
114 Strictly speaking, this is not absolutely necessary, as the agent itself
115 does not make any direct use of the MIB definitions. However, it is
116 advisable to start with this for three reasons:
118 * It provides an initial specification for what is to be implemented.
119 Code development is always easier if you know what you are meant to be
121 * If the new MIB file is read in with the other MIB files,
122 this lets the applications provided with the suite be used to test the
123 new agent, and report (hopefully meaningful) symbolic OIDs and values,
124 rather than the bare numeric forms.
125 (N.B: Remember to tell the application to load the new MIB. See the
126 relevant question in the FAQ)
127 * The tool mib2c uses this description to produce the two code files.
128 This is by far the easiest way to develop a new module.
130 If the intention is to implement a 'standard' MIB module, or a
131 vendor-specific one, then the construction of this file will have already
132 been done for you. If the intention is to provide a totally new, private
133 module, then you will need to write this yourself, in addition to the agent
135 A description of MIB file format and syntax is beyond the scope of this
136 document, and most books on SNMP management should provide some information
137 on this subject. One book which concentrates on this is
139 Understanding SNMP MIBS
140 (Perkins & McGinnis, Prentice Hall, ISBN 0-13-437708-7).
142 This blatant plug is wholly unrelated to the fact that David Perkins is an
143 active member of the development group, and is regarded as our resident
144 "protocol guru and policeman". (In fact, this book concentrates on MIB
145 files in rather more detail than is appropriate in more general SNMP works).
146 Information on other books covering SNMP and Network Management more generally
147 is available on the SimpleWeb site (among other places).
148 See the FAQ for more details.
153 One word of advice - even if you are developing a totally private MIB
154 module, you will still need to position this somewhere within the overall
155 MIB tree. Please do NOT simply choose a location "at random". Any such is
156 likely to have either been assigned to some other organisation, or may be so
157 assigned some time in the future. However much you may regard your project
158 as a totally internal affair, such projects have a tendency to exceed their
159 expected scope, both in terms of lifetime and distribution (not to mention
160 the potential OID clash if you subsequently need to use elements from the
161 legitimate owner's tree).
162 It is simple and cheap (i.e. free!) to obtain your own official segment of
163 the MIB tree (see http://www.iana.org for an application form), and having
164 done so, you then have complete global authority over it. If you have
165 problems with this, it's worth contacting the development team (email:
166 net-snmp-coders@lists.sourceforge.net) for advice. Please do think to the
167 future, and be a good Net citizen by using a legitimately assigned OID as
168 the root of your new MIB.
173 The next point to consider, whether writing by hand or using mib2c,
174 implementing an existing MIB, or writing a new one, is whether and how to
175 divide up the MIB tree. This is a purely internal implementation decision,
176 and will not be visible to management applications querying the agent. A
177 sensible choice of partitioning will result in a simpler, clearer
178 implementation, which should ease both the initial development and
179 subsequent maintenance of the module.
180 Unfortunately, this choice is one of the module-specific decisions, so must
181 be made on a case-by-case basis. For a simple, self-contained module, it may
182 well be reasonable to implement the module as a single block (examples
183 include the SNMP statistics subtree RFC 1907 or the TCP subtree RFC 2011).
184 More complex and diverse modules (such as the Host Resources MIB - RFC 1514)
185 are more naturally considered as a number of individual sub-modules.
186 Some guidelines to bear in mind when deciding on this division:
188 * A MIB sub-tree consisting purely of scalar objects with a common
189 OID prefix would normally be handled in a single implementation module;
190 * Separate scalar subtrees would normally be in different implementation
192 * A table can either be handled within the same implementation module
193 as related scalar objects in the same subtree, or in a separate
194 implementation module;
195 * Variables that rely on the same underlying data structure to retrieve
196 their values, should probably be in the same implementation module (and
197 conversely, (though less so) those that don't, shouldn't).
199 As an initial rule of thumb, a good initial division is likely to be
200 obtained by treating each table and each scalar sub-tree separately. This
201 can be seen in the current agent, where most of the MIB-II modules (RFC
202 1213) are implemented in separate files (see the files under mibgroup/mibII).
203 Note that many of these combine scalar and table handling in the same file,
204 though they are implemented using separate routines.
205 This is also the approach used by mib2c, which constructs a single pair of
206 code files, but uses a separate routine for each table (and another for all
207 the scalar variables).
208 Ultimately, the final consideration (concerning the underlying data) is
209 the most important, and should guide the basic division. For example, the
210 Host Resources Running Software and Running Software Performance modules,
211 while separate in the MIB tree, use the same underlying kernel data and so
212 are implemented together.
217 The final requirement at this stage is to choose a name for each
218 implementation module. This should be reasonably short, meaningful, unique
219 and unlikely to clash with other (existing or future) modules. Mib2c uses
220 the label of the root node of the MIB sub-tree as this name, and this is a
221 reasonable choice in most cases.
222 Recent changes to the agent code organisation have introduced the idea of
223 module groups of related implementation modules. This is used, for example,
224 to identify the constituent modules of a 'split' MIB (such as the Host
225 Resources MIB), or those relating to a particular organisation (such as
227 As with the division, this naming and grouping is a purely internal matter,
228 and is really only visible when configuring and compiling the agent.
230 So much for the MIB file. The next part considers the C header file.
232 3. The C code header file
233 =========================
235 If the MIB file is the definition of the module for external network
236 management applications (where applications includes network management
237 personnel!), then the header file has traditionally served effectively the
238 same purpose for the agent itself.
239 Recent changes to the recommended code structure has resulted in the header
240 file becoming increasingly simpler. It now simply contains definitions of the
241 publically visible routines, and can be generated completely by mib2c.
246 For those interested in the details of this file (for example, if coding a
247 module by hand), then the details of these definitions are as follows. Every
248 header file will have the following two function prototype definitions
250 extern void init_example (void);
251 extern FindVarMethod var_example;
253 If the module includes any tables, or other collections of variables that
254 are implemented in separate routines, then this second definition will be
255 repeated for each of these.
256 In addition, if any of the variables can be SET (and it is intended to
257 implement them as such), there will be a function prototype definitions for
258 each of these, of the form:
260 extern WriteMethod write_varName;
262 These prototypes are in fact typedef'ed in <agent/snmp_vars.h>.
267 This header file is also used to inform the compilation system of any
268 dependancies between this module and any others. There is one utility module
269 which is required by almost every module, and this is included using the
273 (which is produced automatically by mib2c). This same syntax can be used to
274 trigger the inclusion of other related modules. An example of this can be
275 seen in mibII/route_write.h which relies on the mibII/ip module, thus:
277 config_require( mibII/ip )
279 One use of this directive is to define a module group, by supplying a header
280 file consisting exclusively of such config_require directives. It can then
281 be included or excluded from the agent very simply. Examples of this can be
282 seen in mibgroup/mibII.h or mibgroup/host.h, which list the consituent
283 sub-modules of the MIB-II and Host Resources MIBs respectively.
288 Most of the information in this file is (understandably) aimed at the network
289 management agent itself. However, there is one common header file directive
290 that is actually intended to affect the utility commands that are included
291 within the full distribution:
293 config_add_mib( HOST-RESOURCES-MIB )
295 This is used to add the MIB file being implemented to the default list of
296 MIBs loaded by such commands. This means that querying the agent will return
297 informative names and values, rather than the raw numeric forms that SNMP
298 actually works with. Of course, it is always possible for the utilities
299 to specify that this MIB should be loaded anyway. But specifying this file
300 within the module header file is a useful hint that a particular MIB should
301 be loaded, without needing to ask for it explicitly.
302 Note that this will only affect the binaries compiled as part of the same
303 configuration run. It will have no effect on pre-installed binaries, or
304 those compiled following a different configuration specification.
309 The other common element within the header file defines a set of "magic
310 numbers" - one for each object within the implementation module. In fact,
311 this can equally well appear within the main code file, as part of the
312 variable structure (which will be described in the next part).
313 This is the technique used by mib2c, but most handcrafted modules have
314 tended to define these as part of the header file, probably for clarity.
316 The only necessity is that the names and values are distinct (or more
317 precisely, the values are distinct within a single variable handling routine).
318 In practise, they tend to be defined using integers incrementing from 1,
319 or as the same as the final sub-identifier of the corresponding MIB object
320 (or indeed both, as these are frequently themselves successive integers).
321 This is not mandatory, and a counter-example can be seen in the
322 example module, where two of the object form a sub-tree, and the corresponding
323 magic numbers are based on the final *two* sub-identifiers (to ensure that
324 the values are unique). But this construction is definitely unusual, and
325 the majority of modules simply use successive integers.
327 Header file protection
328 ----------------------
330 Normally, the only other contents of the header file will be the
331 #ifndef/#define/#endif statements surrounding the whole file. This is used
332 to ensure that the header file is only included once by any source code file
333 (or more accurately, that there is no effect if it is inadvertantly included
335 Again, as with the rest of the header file, this is generated automatically
338 Having finished all the preparatory work (or let mib2c deal with it), the
339 next part starts to look at the code file that actually implements the
342 4. Core structure of the implementation code
343 ============================================
345 The core work of implementing the module is done in the C code file. As
346 indicated earlier, much of the detail of this will be dependent on the
347 particular module being implemented, and this can only be described by the
348 individual programmer concerned.
349 However, there is a fairly clearly defined framework that the implementation
350 will need to follow, though this varies slightly depending on the style of
351 the module being implemented (in particular whether it forms a table or a
352 series of individual values). The differences will be covered in the
353 following pages, but we first need to consider the overall shape of the
354 framework, and the elements that are common to all styles. These are
355 essentially the compulsory routines, the common header definitions, and
356 assorted initialisation code.
357 As with the header file, most of this will be generated automatically by
363 Certain header files are either compulsory, or required so frequently that
364 they should be included as a matter of course. These are as follows:
366 #include <config.h> // local SNMP configuration details
367 #include "mib_module_config.h" // list of which modules are supported
377 #include <sys/types.h>
379 All of these will usually be the first files to be included.
381 #include "mibincl.h" // Standard set of SNMP includes
382 #include "util_funcs.h" // utility function declarations
383 #include "read_config.h" // if the module uses run-time
384 // configuration controls
385 #include "auto_nlist.h" // structures for a BSD-based
386 // kernel using nlist
389 #include "name.h" // the module-specific header
391 These conventionally come at the end of the list of includes. In between
392 will come all the standard system-provided header files required for the
393 library functions used in the file.
398 Much of the code defining the contents of the MIB has traditionally been
399 held in the header file. However, much of this has slowly migrated to the
400 code file, and this is now the recommended location for it (as typified by
401 the output of mib2c).
402 The main element of this is a variable structure specifying the details of
403 the objects implemented. This takes the form of an unconstrained array of
404 type struct variableN (where N is the length of the longest suffix in the
407 struct variable2 example_variables[] = {
408 <individual entries go here>
411 Each entry corresponds to one object in the MIB tree (or one column in the
412 case of table entries), and these should be listed in increasing OID order.
413 A single entry consists of six fields:
415 * a magic number (the #defined integer constant described above)
416 * a type indicator (from the values listed in <snmplib/snmp_impl.h>)
417 * an access indicator (essentially RWRITE or RONLY)
418 * the name of the routine used to handle this entry
419 * the length of the OID suffix used, and
420 * an array of integers specifying this suffix (more on this in a moment)
422 Thus a typical variable entry would look like:
424 { EXAMPLESTRING, ASN_OCTET_STR, RONLY, var_example, 1, {1}}
426 If the magic numbers have not been defined in the header file, then they
427 should be defined here, usually comming immediately before the corresponding
428 variable entry. This is the technique used by mib2c.
430 Note that in practise, only certain sizes of the structure variableN
431 are defined (listed in <agent/var_struct.h>), being sufficient to meet the
432 common requirements. If your particular module needs a non-supported value,
433 the easiest thing is simply to use the next largest value that is supported.
435 The module also needs to declare the location within the MIB tree where
436 it should be registered. This is done using a declaration of the form
438 oid example_variables_oid[] = { 1,3,6,1,4,1,2021,254 }
440 where the contents of the array give the object identifier of the root of
443 Module initialisation
444 ---------------------
446 Many modules require some form of initialisation before they can start
447 providing the necessary information. This is done by providing a routine
448 called init_{name} (where {name} is the name of the module).
449 This routine is theoretically optional, but in practise is required to
450 register this module with the main agent at the very least. This specifies
451 the list of variables being implemented (from the variableN structure)
452 and declare where these fit into the overall MIB tree.
454 This is done by using the REGISTER_MIB macro, as follows:
456 REGISTER_MIB( "example", example_variables, variable2,
457 example_variables_oid );
459 where "example" is used for identification purposed (and is usually the name
460 being used for the module), example_variables is the structure defining the
461 variables being implemented, variable2 is the type used for this structure,
462 and example_variables_oid is the location of the root.
464 In fact, this macro is simply a wrapper round the routine register_mib(),
465 but the details of this can safely be ignored, unless more control over the
466 registration is required.
468 One common requirement, particularly on older operating systems or for the
469 more obscure areas of the system, is to be able to read data directly from
470 kernel memory. The preparation for this is typically done here by one or
471 more statements of the form
474 auto_nlist( {NAME}_SYMBOL, 0, 0);
477 where {NAME}_SYMBOL is defined as part of the system-specific configuration,
478 to be the name of the appropriate kernel variable or data structure. (The
479 two 0 values are because the kernel information is simply being primed at
480 this point - this call will be reused later when the actual values are
481 required). Note that this is probably the first thing described so far which
482 isn't provided by mib2c!
484 Other possibilities for initialisation may include registering config file
485 directive handlers (which are documented in the read_config(5) man page), and
486 registering the MIB module (either in whole or in part) in the sysOR table.
487 The first of these is covered in the example module, and the second in many
488 of the other modules within the main UCD distribution.
493 The other obligatory routine is that which actually handles a request for a
494 particular variable instance. This is the routine that appeared in the
495 variableN structure, so while the name is not fixed, it should be the same
497 This routine has six parameters, which will be described in turn.
499 Four of these parameters are used for passing in information about the
500 request, these being:
503 // The entry in the variableN array from the
504 // header file, for the object under consideration.
505 // Note that the name field of this structure has been
506 // completed into a fully qualified OID, by prepending
507 // the prefix common to the whole array.
508 oid *name; // The OID from the request
509 int *length; // The length of this OID
510 int exact; // A flag to indicate whether this is an exact
511 // request (GET/SET) or an 'inexact' one (GETNEXT)
513 Four of the parameters are used to return information about the answer.
514 The function also returns a pointer to the actual data for the variable
515 requested (or NULL if this data is not available for any reason).
516 The other result parameters are:
518 oid *name; // The OID being returned
519 int *length; // The length of this OID
520 int *var_len; // The length of the answer being returned
521 WriteMethod **write_method;
522 // A pointer to the SET function for this variable
524 Note that two of the parameters (name and length) serve a dual purpose,
525 being used for both input and output.
527 The first thing that this routine needs to do is to validate the request, to
528 ensure that it does indeed lie in the range implemented by this particular
529 module. This is done in slightly different ways, depending on the style of
530 the module, so this will be discussed in more detail later.
531 At the same time, it is common to retrieve some of the information needed
532 for answering the query.
534 Then the routine uses the Magic Number field from the vp parameter to determine
535 which of the possible variables being implemented is being requested. This is
536 done using a switch statement, which should have as many cases as there are
537 entries in the variableN array (or more precisely, as many as specify this
538 routine as their handler), plus an additional default case to handle an
540 Each branch of the switch statement needs to ensure that the return
541 parameters are filled in correctly, set up a (static) return variable with
542 the correct data, and then return a pointer to this value. These can be done
543 separately for each branch, or once at the start, being overridden in
544 particular branches if necessary.
546 In fact, the default validation routines make the assumption that the
547 variable is both read-only, and of integer type (which includes the COUNTER
548 and GAUGE types among others), and set the return paramaters write_method and
549 var_len appropriately. These settings can then be corrected for those cases
550 when either or both of these assumptions are wrong. Examples of this can be
551 seen in the example module.
552 EXAMPLEINTEGER is writeable, so this branch sets the write_method parameter,
553 and EXAMPLEOBJECTID is not an integer, so this branch sets the var_len
554 parameter. In the case of EXAMPLESTRING, both assumptions are wrong, so this
555 branch needs to set both these parameters explicitly.
557 Note that because the routine returns a pointer to a static result, a
558 suitable variable must be declared somewhere for this. Two global variables
559 are provided for this purpose - long_return (for integer results) and
560 return_buf (for other types). This latter is a generic array (of type
561 u_char) that can contain up to 256 bytes of data. Alternatively, static
562 variables can be declared, either within the code file, or local to this
563 particular variable routine. This last is the approach adopted by mib2c,
564 which defines four such local variables, (long_ret, string, objid and c64).
569 Most of the code described here is generated by mib2c. The main exceptions
570 (which therefore need to be provided by the programmer) are
572 * Any initialisation, other than the basic registration
573 (including kernel data initialisation, config file handling, or sysOR
575 * Retrieving the necessary data, and setting the appropriate return
577 * The var_len (and possibly write_method) return parameters for variable
578 types that are not recognised by mib2c
579 * The contents of any write routines (see later).
581 Everything else should be useable as generated.
583 This concludes the preliminary walk-through of the general structure of the
584 C implementation. To fill in the details, we will need to consider the
585 various styles of module separately. The next part will look at scalar (i.e.
586 non-table based) modules.
588 5. Non-table-based modules
589 ==========================
591 Having looked at the general structure of a module implementation, it's now
592 time to look at this in more detail. We'll start with the simplest style of
593 module - a collection of independent variables. This could easily be
594 implemented as a series of completely separate modules - the main reason for
595 combining them is to avoid the proliferation of multiple versions of very
598 Recall that the variable handling routine needs to cover two distinct
599 purposes - validation of the request, and provision of the answer. In this
600 style of module, these are handled separately. Once again, mib2c does much
601 of the donkey work, generating the whole of the request validation code (so
602 the description of this section can be skipped if desired), and even
603 providing a skeleton for returning the data. This latter still requires some
604 input from the programmer, to actually return the correct results (rather
610 This is done using a standard utility function header_generic. The
611 parameters for this are exactly the same as for the main routine, and are
612 simply passed through directly. It returns an integer result, as a flag to
613 indicate whether the validation succeeded or not.
614 If the validation fails, then the main routine should return immediately,
615 leaving the parameters untouched, and indicate the failure by returning a
616 NULL value. Thus the initial code fragment of a scalar-variable style
617 implementation will typically look like:
620 var_system(vp, name, length, exact, var_len, write_method)
622 if (header_generic(vp, name, length, exact, var_len, write_method)
629 Although the utility function can be used as a "black box", it's worth
630 looking more closely at exactly what it does (since the table-handling
631 modules will need to do something fairly similar). It has two (or possibly
632 three) separate functions:
634 * checking that the request is valid,
635 * setting up the OID for the result,
636 * and (optionally) setting up default values for the other return
639 In order to actually validate the request, the header routine first needs to
640 construct the OID under consideration, in order to compare it with that
641 originally asked for. The driving code has already combined the OID prefix
642 (constant throughout the module) with the entry-specific suffix, before
643 calling the main variable handler. This is available via the name field of
644 the parameter vp. For a scalar variable, completing the OID is therefore
645 simply a matter of appending the instance identifier 0 to this. The full OID
646 is built up in a local oid array newname defined for this purpose.
647 This gives the following code fragment:
650 header_generic(vp, name, length, exact, var_len, write_method)
652 oid newname[MAX_OID_LEN];
654 memcpy((char *)newname, (char *)vp->name,
655 (int)vp->namelen * sizeof(oid));
656 newname[ vp->namelen ] = 0;
661 Having formed the OID, this can then be compared against the variable
662 specified in the original request, which is available as the name parameter.
663 This comparison is done using the snmp_oid_compare function, which takes the
664 two OIDs (together with their respective lengths), and returns -1, 0 or 1
665 depending on whether the first OID precedes, matches or follows the second.
667 In the case of an 'exact' match (i.e. a GET/SET/etc), then the request is
668 only valid if the two OIDs are identical (snmp_oid_compare returns 0). In
669 the case of a GETNEXT (or GETBULK) request, it's valid if the OID being
670 considered comes after that of the original request (snmp_oid_compare
673 This gives the code fragment
675 result = snmp_oid_compare(name, *length, newname, (int)vp->namelen + 1);
676 // +1 because of the extra instance sub-identifier
677 if ((exact && (result != 0)) // GET match fails
678 || (!exact && (result >= 0))) // GETNEXT match fails
679 return(MATCH_FAILED);
681 Note that in this case, we're only interested in the single variable
682 indicated by the vp parameter. The fact that this module may well implement
683 other variables as well is ignored. The 'lexically next' requirement of the
684 GETNEXT request is handled by working through the variable entries in order
685 until one matches. And yes, this is not the most efficient implementation
687 Note that in releases prior to 3.6, the snmp_oid_compare function was called
690 Finally, having determined that the request is valid, this routine must
691 update the name and length parameters to return the OID being processed. It
692 also sets default values for the other two return parameters.
694 memcpy( (char *)name,(char *)newname,
695 ((int)vp->namelen + 1) * sizeof(oid));
696 *length = vp->namelen + 1;
697 *write_method = 0; // Non-writeable
698 *var_len = sizeof(long); // default to integer results
699 return(MATCH_SUCCEEDED);
701 These three code fragments combine to form the full header_generic code
702 which can be seen in the file util_funcs.c
704 Note: This validation used to be done using a separate function for each
705 module (conventionally called header_{name}), and many modules may still be
706 coded in this style. The code for these are to all intents and purposes
707 identical to the header_generic routine described above.
712 The other main job of the request handling routine is to retrieve any
713 necessary data, and return the appropriate answer to the original request.
714 This must be done even if mib2c is being used to generate the framework of
715 the implementation. As has been indicated earlier, the different cases are
716 handled using a switch statement, with the Magic Number field of the vp
717 parameter being used to distinguish between them.
718 The data necessary for answering the request can be retrieved for each
719 variable individually in the relevant case statement (as is the case with
720 the system group), or using a common block of data before processing the
721 switch (as is done for the ICMP group, among others).
723 With many of the modules implemented so far, this data is read from a kernel
724 structure. This can be done using the auto_nlist routine already mentioned,
725 providing a variable in which to store the results and an indication of its
726 size (see the !HAVE_SYS_TCPIPSTATS_H case of the ICMP group for an example).
727 Alternatively, there may be ioctl calls on suitable devices, specific system
728 calls, or special files that can be read to provide the necessary
731 If the available data provides the requested value immediately, then the
732 individual branch becomes a simple assignment to the appropriate static
733 return variable - either one of the global static variables (e.g. long_return)
734 or the local equivalents (such as generated by mib2c).
735 Otherwise, the requested value may need to be calculated by combining two or
736 more items of data (e.g. IPINHDRERRORS in mibII/ip.c) or by applying a
737 mapping or other calculation involving available information (e.g.
738 IPFORWARDING from the same group).
740 In each of these cases, the routine should return a pointer to the result
741 value, casting this to the pseudo-generic (u_char *)
743 So much for the scalar case. The next part looks at how to handle simple
749 Having considered the simplest style of module implementation, we now turn
750 our attention to the next style - a simple table. The tabular nature of
751 these is immediately apparent from the MIB definition file, but the
752 qualifier "simple" deserves a word of explanation.
753 A simple table, in this context, has four characteristics:
755 1. It is indexed by a single integer value;
756 2. Such indices run from 1 to a determinable maximum;
757 3. All indices within this range are valid;
758 4. The data for a particular index can be retrieved directly
759 (e.g. by indexing into an underlying data structure).
761 If any of the conditions are not met, then the table is not a pure simple
762 one, and the techniques described here are not applicable. The next section
763 of this guide will cover the more general case. (In fact, it may be possible
764 to use the bulk of the techniques covered here, though special handling will
765 be needed to cope with the invalid assumption or assumptions). Note that
766 mib2c assumes that all tables are simple.
768 As with the scalar case, the variable routine needs to provide two basic
769 functions - request validation and data retrieval.
774 This is provided by the shared utility routine header_simple_table. As with
775 the scalar header routine, this takes the same parameters as the main
776 variable routine, with one addition - the maximum valid index. Mib2c
777 generates a dummy token for this, which must be replaced by the appropriate
779 As with the header routine, it also returns an indication of whether the
780 request was valid, as well as setting up the return parameters with the
781 matching OID information, and defaults for var_len and write_method.
782 Note that in releases prior to 3.6, this job was performed by the routine
783 checkmib. However, the return values of this were the reverse of those for
784 generic_header and header_simple_table. A version of checkmib is still
785 available for compatability purposes, but you are encouraged to use
786 header_simple_table instead.
788 The basic code fragment (see ucd-snmp/disk.c) is therefore of the form:
791 var_extensible_disk(vp, name, length, exact, var_len, write_method)
793 if (header_simple_table(vp,name,length,exact,var_len,write_method,numdisks)
801 Note that the maximum index value parameter does not have to be a
802 permanently fixed constant. It specifies the maximum valid index at the time
803 the request is processed, and a subsequent request may have a different
805 An example of this can be seen in mibII/sysORTable.c where the table is held
806 purely internally to the agent code, including its size (and hence the
807 maximum valid index). This maximum could also be retrieved via a system
808 call, or via a kernel data variable.
813 As with the scalar case, the other required function is to retrieve the data
814 requested. However, given the definition of a simple table this is simply a
815 matter of using the single, integer index sub-identifier to index into an
816 existing data structure. This index will always be the last index of the OID
817 returned by header_simple_table, so can be obtained as name[*length-1].
818 A good example of this type of table can be seen in ucd-snmp/disk.c
820 With some modules, this underlying table may be relatively large, or only
821 accessible via a slow or cumbersome interface. The implementation described
822 so far may prove unacceptably slow, particularly when walking a MIB tree
823 requires the table to be loaded afresh for each variable requested.
825 In these circumstances, a useful technique is to cache the table when it is
826 first read in, and use that cache for subsequent requests. This can be done
827 by having a separate routine to read in the table. This uses two static
828 variables, one a structure or array for the data itself, and the other an
829 additional timestamp to indicate when the table was last loaded. When a call
830 is made to this routine to "read" the table, it can first check whether the
831 cached table is "new enough". If so, it can return immediately, and the
832 system will use the cached data.
833 Only if the cached version is sufficiently old that it's probably out of
834 date, is it necessary to retrieve the current data, updating the cached
835 version and the timestamp value.
836 This is particularly useful if the data itself is relatively static, such as
837 a list of mounted filesystems. There is an example of this technique in the
838 Host Resources implementation.
840 As with the scalar case, mib2c simply provides placeholder dummy return
841 values. It's up to the programmer to fill in the details.
843 The next part concludes the examination of the detailed implementation by
844 looking at more general tables.
849 Some table structures are not suitable for the simple table approach, due to
850 the failure of one or more of the assumptions listed earlier. Perhaps they
851 are indexed by something other than a single integer (such as a 4-octet IP
852 address), or the maximum index is not easily determinable (such as the
853 interfaces table), or not all indices are valid (running software), or the
854 necessary data is not directly accessible (interfaces again).
855 In such circumstances, a more general approach is needed. In contrast with
856 the two styles already covered, this style of module will commonly combine
857 the two functions of request validation and data retrieval. Note that mib2c
858 will assume the simple table case, and this will need to be corrected.
860 General table algorithm
861 -----------------------
863 The basic algorithm is as follows:
865 Perform any necessary initialization, then walk through the
866 underlying instances, retrieving the data for each one, until the
867 desired instance is found. If no valid entry is found, return
870 For an exact match (GET and similar), identifying the desired instance is
871 trivial - construct the OID (from the 'vp' variable parameter and the index
872 value or values), and see whether it matches the requested OID.
873 For GETNEXT, the situation is not quite so simple. Depending on the
874 underlying representation of the data, the entries may be returned in the
875 same order as they should appear in the table (i.e. lexically increasing by
876 index). However, this is not guaranteed, and the natural way of retrieving
877 the data may be in some "random" order. In this case, then the whole table
878 needs to be traversed for each request. in order to determine the
879 appropriate successor.
880 This random order is the worst case, and dictates the structure of the code
881 used in most currently implemented tables. The ordered case can be regarded
882 as a simplification of this more general one.
884 The algorithm outlined above can now be expanded into the following
887 Init_{Name}_Entry(); // Perform any necessary initialisation
889 while (( index = Get_Next_{Name}_Entry() ) != EndMarker ) {
890 // This steps through the underlying table,
891 // returning the current index,
892 // or some suitable end-marker when all
893 // the entries have been examined.
894 // Note that this routine should also return the
895 // data for this entry, either via a parameter
896 // or using some external location.
898 construct OID from vp->name and index
899 compare new OID and request
902 if finished // exact match, or ordered table
903 break; // so don't look at any more entries
907 // Otherwise, we need to loop round, and examine
908 // the next entry in the table. Either because
909 // the entry wasn't valid for this request,
910 // or the entry was a possible "next" candidate,
911 // but we don't know that there isn't there's a
912 // better one later in the table.
915 if no saved data // Nothing matched
918 // Otherwise, go on to the switch handling
919 // we've already covered in the earlier styles.
921 This is now very close to the actual code used in many current
922 implementations (such as the the routine header_ifEntry in
923 mibII/interfaces.c). Notice that the pseudo-code fragment if valid expands
926 if ((exact && (result == 0)) ||
927 // GET request, and identical OIDs
928 (!exact && (result < 0)) )
929 // GETNEXT, and candidate OID is later
930 // than requested OID.
932 This is a very common expression, that can be seen in most of the table
935 Notice also that the interfaces table returns immediately the first valid
936 entry is found, even for GETNEXT requests. This is because entries are
937 returned in lexical order, so the first succeeding entry will be the one
939 (As an aside, this also means that the underlying data can be saved
940 implicitly within the 'next entry' routine - not very clean, but it saves
941 some unnecessary copying).
943 The more general case can be seen in the TCP and UDP tables (see mibII/tcp.c
944 and mibII/udp.c). Here, the if valid fragment expands to:
946 if ( exact && (result == 0)) {
950 else if (!exact && (result < 0)) {
951 if ( .... ) { // no saved OID, or this OID
952 // precedes the saved OID
953 // save this OID into 'lowest'
954 // save the results into Lowinpcb
955 // don't break, since we still need to look
956 // at the rest of the table
960 The GET match handling is just as we've already seen - is this the requested
961 OID or not. If so, save the results and move on to the switch statement.
962 The GETNEXT case is more complicated. As well as considering whether this
963 is a possible match (using the same test we've already seen), we also have to
964 check whether this is a better match than anything we've already seen. This
965 is done by comparing the current candidate (newname) with the best match found
967 Only if this extra comparison shows that the new OID is earlier than the
968 saved one, do we need to save both the new OID, and any associated data
969 (such as the inpcb block, and state flag). But having found one better
970 match, we don't know that there isn't an even better one later on. So we
971 can't break out of the enclosing loop - we need to keep going and examine
972 all the remaining entries of the table.
974 These two cases (the TCP and UDP tables) also show a more general style of
975 indexing. Rather than simply appending a single index value to the OID
976 prefix, these routines have to add the local four-octet IP address plus port
977 (and the same for the remote end in the case of the TCP table). This is the
978 purpose of the op and cp section of code that precedes the comparison.
980 These two are probably among the most complex cases you are likely to
981 encounter. If you can follow the code here, then you've probably cracked the
982 problem of understanding how the agent works.
984 Finally, the next part discusses how to implement a writable (or SETable)
985 object in a MIB module.
987 8. How to implement a SETable object
988 ====================================
990 Finally, the only remaining area to cover is that of setting data - the
991 handling of SNMPSET. Particular care should be taken here for two reasons.
993 Firstly, any errors in the earlier sections can have limited effect. The
994 worst that is likely to happen is that the agent will either return invalid
995 information, or possibly crash. Either way, this is unlikely to affect the
996 operation of the workstation as a whole. If there are problems in the
997 writing routine, the results could be catastrophic (particularly if writing
998 data directly into kernel memory).
1000 Secondly, this is the least well understood area of the agent, at least by
1001 the author. There are relatively few variables that are defined as READ-WRITE
1002 in the relevant MIBs, and even fewer that have actually been implemented as
1003 such. I'm therefore describing this from a combination of my understanding
1004 of how SETs ought to work, personal experience of very simple SET handling
1005 and what's actually been done by others (which do not necessarily coincide).
1007 There are also subtle differences between the setting of simple scalar
1008 variables (or individual entries within a table), and the creation of a new
1009 row within a table. This will therefore be considered separately.
1011 With these caveats, and a healthy dose of caution, let us proceed. Note that
1012 the UCD-SNMP development team can accept no responsibility for any damage or
1013 loss resulting from either following or ignoring the information presented
1014 here. You coded it - you fix it!
1019 The heart of SET handling is the write_method parameter from the variable
1020 handling routine. This is a pointer to the relevant routine for setting the
1021 variable in question. Mib2c will generate one such routine for each setable
1022 variable. This routine should be declared using the template
1028 u_char var_val_type,
1034 Most of these parameters are fairly self explanatory:
1035 The last two hold the OID to be set, just as was passed to the main variable
1038 The second, third and fourth parameters provide information about the new
1039 desired value, both the type, value and length. This is very similar to the
1040 way that results are returned from the main variable routine.
1042 The return value of the routine is simply an indication of whether the
1043 current stage of the SET was successful or not. We'll come back to this in a
1044 minute. Note that it is the responsibility of this routine to check that the
1045 OID and value provided are appropriate for the variable being implemented.
1046 This includes (but is not limited to) checking:
1048 * the OID is recognised as one this routine can handle
1049 (this should be true if the routine only handles the one variable, and
1050 there are no errors in the main variable routine or driving code, but
1051 it does no harm to check).
1052 * the value requested is the correct type expected for this OID
1053 * the value requested is appropriate for this OID
1054 (within particular ranges, suitable length, etc, etc)
1056 There are two parameters remaining to be considered.
1058 The fifth parameter, statP, is the value that would be returned from a GET
1059 request on this particular variable. It could be used to check that the
1060 requested new value is consistent with the current state, but its main use
1061 is to denote that a new table row is being created.
1062 In most cases (particularly when dealing with scalar values or single elements
1063 of tables), you can normally simply ignore this parameter.
1068 The final parameter to consider is the first one - action. To understand
1069 this, it's necessary to know a bit about how SETs are implemented.
1070 The design of SNMP calls for all variables in a SET request to be done "as
1071 if simultaneously" - i.e. they should all succeed or all fail. However, in
1072 practise, the variables are handled in succession. Thus, if one fails, it
1073 must be possible to "undo" any changes made to the other variables in the
1075 This is a well understood requirement in the database world, and is usually
1076 implemented using a "multi-stage commit". This is certainly the mechanism
1077 expected within the SNMP community (and has been made explicit in the work
1078 of the AgentX extensibility group). In other words, the routine to handle
1079 setting a variable will be called more than once, and the routine must be
1080 able to perform the appropriate actions depending on how far through the
1081 process we currently are. This is determined by the value of the action
1084 This is implemented using three basic phases:
1086 RESERVE is used to check the syntax of all the variables provided, that the
1087 values being set are sensible and consistent, and to allocate any resources
1088 required for performing the SET. After this stage, the expectation is that
1089 the set ought to succeed, though this is not guaranteed.
1090 (In fact, with the UCD agent, this is done in two passes - RESERVE1, and
1091 RESERVE2, to allow for dependancies between variables).
1093 If any of these calls fail (in either pass) the write routines are called
1094 again with the FREE action, to release any resources that have been
1095 allocated. The agent will then return a failure response to the requesting
1098 Assuming that the RESERVE phase was successful, the next stage is indicated
1099 by the action value ACTION. This is used to actually implement the set
1100 operation. However, this must either be done into temporary (persistent)
1101 storage, or the previous value stored similarly, in case any of the
1102 subsequent ACTION calls fail.
1103 This can be seen in the example module, where both write routines have
1104 static 'old' variables, to hold the previous value of the relevant object.
1106 If the ACTION phase does fail (for example due to an apparently valid, but
1107 unacceptable value, or an unforeseen problem), then the list of write
1108 routines are called again, with the UNDO action. This requires the routine
1109 to reset the value that was changed to its previous value (assuming it was
1110 actually changed), and then to release any resources that had been
1111 allocated. As with the FREE phase, the agent will then return an indication
1112 of the error to the requesting application.
1114 Only once the ACTION phase has completed successfully, can the final COMMIT
1115 phase be run. This is used to complete any writes that were done into
1116 temporary storage, and then release any allocated resources. Note that all
1117 the code in this phase should be "safe" code that cannot possibly fail (cue
1118 hysterical laughter). The whole intent of the ACTION/COMMIT division is that
1119 all of the fallible code should be done in the ACTION phase, so that it can
1120 be backed out if necessary.
1125 What about creating new rows in a table, I hear you ask. Good Question.
1126 This case can often be detected by the fact that a GET request would have
1127 failed, and hence the fifth parameter, statP, will be null. This contrasts
1128 with changing the values of an element of an existing row, when the statP
1129 parameter would hold the previous value.
1131 The details of precisely how to create a new row will clearly depend on the
1132 underlying format of the table. However, one implementation strategy would
1135 * The first column object to be SET would return a null value from the
1136 var_name routine. This null statP parameter would be the signal
1137 to create a new temporary instance of the underlying data structure,
1138 filled with dummy values.
1139 * Subsequent column objects would return pointers to the appropriate
1140 field of this new data structure from the var_name routine,
1141 which would then be filled in by the write routine.
1142 * Once all the necessary fields had been SET, the completed temporary
1143 instance could be moved into the "standard" structure (or copied,
1144 or otherwise used to set things up appropriately).
1146 However, this is purely a theoretical strategy, and has not been tried
1147 by the author. No guarantees are given as to whether this would actually
1148 work. There are also questions regarding how to handle incomplete
1149 or overlapping SET requests.
1150 Anyone who has experience of doing this, please get in touch!
1152 ------------------------------------------------------------------------
1153 And that's it. Congratulations for getting this far. If you understand
1154 everything that's been said, then you now know as much as the rest of us
1155 about the inner workings of the UCD-SNMP agent. (Well, very nearly).
1156 All that remains is to try putting this into practise. Good luck!
1158 And if you've found this helpful, gifts of money, chocolate, alcohol, and
1159 above all feedback, would be most appreciated :-)
1161 ------------------------------------------------------------------------
1162 Copyright 1999, 2000 - D.T.Shield.
1163 Not to be distributed without the explicit permission of the author.