# Digital TCP/IP Services for OpenVMS
eSNMP Programming and Reference

Previous | Contents

SMI avoids complex data types to simplify the task of implementation and to enhance interoperability. To provided a standard representation of management information, the SMI provides standard techniques for the following:

- Defining the structure of a particular MIB
- Defining individual objects, including the syntax and value of each object
- Encoding object values

## 4.2.1 Assigning Object Identification Codes

Associated with each object in a MIB is an identifier of the ASN.1 type called an object identifier (OID). OIDs are unique integers that follow a hierarchical naming convention.

Each OID has two parts: a pre-assigned portion and a developer-assigned portion. The pre-assigned portion, is always represented on the SMI tree as 1.3.6.1 or iso (1), org (3), dod (6), Internet (1). The second portion is for private development of MIBs.

> Note

> Your organization may require you to register all newly assigned OIDs.

In addition to an OID, you should also assign a name to each object to help with human interpretation.

Figure 4-1 illustrates the SMI hierarchial tree arrangement as specified in RFC 1155.

## 4.2.2 Defining Objects

The consistency of the MIB module is addressed in RFC 1212 which provides textual definitions within object-type macros. These object-type macros consist of the following elements:

- Syntax --- defines the data structure of an object.
- Access --- defines the protections of an object, for example, read-only, read and write, or not accessible.
- Status --- defines the implementation requirements of the object, for example, required, optional, or obsolete.
- Description --- provides a textual definition of the object. Inclusion of this element is optional.
- Index --- defines a row.
- Defval --- populates values of column objects. Inclusion of this element is optional.

Each resource that a MIB manages is represented by an object

Figure 4-1 MIB-II in SMI Tree Structure

# 4.3 Creating a MIB Source File

Creating the MIB source files is basically a four-step process and is described in the following sections:

1. Writing the ASN.1 input files (Section 4.3.1)
2. Processing the input files with the MIB compiler (Section 4.3.2)
3. The Subtree_TBL.H output files (Section 4.3.3)
4. The Subtree_TBL.C output files (Section 4.3.4)

## 4.3.1 Writing the ASN.1 Input Files

Once you have assigned names and OIDs to all of the objects in the MIB, create an ASN.1 source file using ASCII statements.

> Note

> Providing information on ASN.1 syntax and programming is beyond the scope of this guide. For more information on ASN.1 programming, refer to one or more of the documents on this subject provided by the International Organization for Standardization (ISO).

## 4.3.2 Processing the Input Files with the MIB Compiler

The next step is to process each ASN.1 source file with the MIB compiler which generates modules used by the subagent developer. You should run the MIB compiler once for each set of MIB source files that relate to a specific subagent. This means that you should run the MIB compiler once for all of the MIBs associated with a particular subagent. Processing files in this manner allows you to process all of a subagent's MIB by issuing a single command. To update a MIB, you must re-issue the command and all of the associated MIBs.

Each ASN.1 input file that is processed in the MIB compiler yeilds two output files: a <subtree>_TBL.H file and a <subtree>_TBL.C file.

The syntax for the MIBCOMP command that processes the input file is as follows:

    $ MIBCOMP  <MIB-source-files>  <subtree>
    [/PREFIX=<name>] [/PRINT]

Table 4-1 defines the MIBCOMP command qualifiers.

Table 4-1 MIBCOMP Command Definition
Qualifier/Option | Definition
--- | ---
<MIB-source-files> | A list of MIB source files, specified in the order of hierarchy precedence.
<subtree> | The subtree on which you wish to the base the OID structure.
/PREFIX=<name> | String with which you wish to prefix all generated names.
/PRINT | Display entire MIB subtree.

The following is an example of processing input files with the MIB compiler:

    $ mibcomp  RFC1442.MY, CHESS_MIB.MY  DEC

    Processing RFC1442.MY
    Processing CHESS_MIB.MY
    11 objects written to dec_tbl.c
    11 objects written to dec_tbl.h

    $ mibcomp RFC1442.MY, CHESS_MIB.MY dec /print

    Processing RFC1442.MY
    Processing CHESS_MIB.MY
    Dump of objects in lexical order
        -- This file created by program 'snmpi -p'

    ccitt                                    0
    iso                                      1
     internet                                1.3.6.1
      directory                              1.3.6.1.1
      mgmt                                   1.3.6.1.2
      experimental                           1.3.6.1.3
      private                                1.3.6.1.4
       enterprises                           1.3.6.1.4.1
        dec                                  1.3.6.1.4.1.36
         ema                                 1.3.6.1.4.1.36.2
          sysobjectids                       1.3.6.1.4.1.36.2.15
           decosf                            1.3.6.1.4.1.36.2.15.2
            chess                            1.3.6.1.4.1.36.2.15.2.99

                                    .     .     .

      security                               1.3.6.1.5
      snmpV2                                 1.3.6.1.6
       snmpDomains                           1.3.6.1.6.1
       snmpProxys                            1.3.6.1.6.2
       snmpModules                           1.3.6.1.6.3
    joint_iso_ccitt                          2
    --------------------------
    11 objects written to dec_tbl.c
    11 objects written to dec_tbl.h

    $

## 4.3.3 The Subtree_TBL.H Output Files

The file <subtree>_TBL.H contains the following information:

- A declaration of the subtree structure
- Index definitions for each MIB variable in the subtree
- Enumeration definitions for MIB variables with enumerated values
- MIB group data structure definitions
- Method routine function prototypes

The first section of the file is a declaration of the subtree structure. The subtree is automatically initialized by code in the <subtree>_TBL.C file. A pointer to this structure is passed to the esnmp_register routine to register a subtree with the master agent. All access to the object table for this subtree is through this pointer. The declaration has the following form:

extern SUBTREE subtree subtree;

The second section of the file contains index definitions for each MIB variable in the SUBTREE of the form:

#define I_ mib-variable nnn

These values are unique for each MIB variable within a subtree and are the index into the object table for this MIB variable. These values are also generally used to differentiate between variables that are implemented in the same method routine so they can be used in a switch operation.

The third section contains enumeration definitions for those integer MIB variables that are defined with enumerated values, as follows:

#define D_ mib-variable_enumeration-name value

These are useful since they describe the value that enumerated integer MIB variables may take on. For example:

    /* enumerations for gameEntry group */
       #define   D_gameStatus_complete         1
       #define   D_gameStatus_underway         2
       #define   D_gameStatus_delete           3

The next section contains the MIB group data structure definitions of the form: typedef struct xxx{

         type        mib-variable;
       .
       .
       .
         char        mib-variable_mark;
       .
       .
       .
         } mib-group_type

One of these data structures is emitted by the MIB compiler for each MIB group within the subtree. Each structure definition contains a field representing each MIB variable within the group. In addition to the MIB variable fields, the structure includes a 1-byte mib-variable_mark field for each variable. You can use these for maintaining status of a MIB variable. For example, the following is the group structure for the chess MIB:

    typedef struct _chess_type {
        OID   ches;
        int   chessMaxGames;
        int   chessNumGames;

        char chessProductID_mark;
        char chessMaxGames_mark;
        char chessNumGames_mark;
    } chess_type;

Although MIB group structures are provided for your use, you are not required to use them. You can use the structure that works best with your method routines.

The next section describes the method routine prototypes. Each MIB group within the subtree has a method routine prototype defined. A MIB group is a collection of MIB variables that are leaf nodes that share a common parent node.

There is always a function prototype for the method routine that handles the Get, GetNext, and GetBulk operations. If the group contains any writeable variables, there is also a function prototype for the method routine that handles Set operations. Pointers to these routines appear in the subtree's object table which is initialized in the <subtree>_TBL.C module. You must write method routines for each prototype that is defined, as follows:

extern int<mib-group>_ get(METHOD *method)

extern int<mib-group>_ set(METHOD *method)

For example:

    extern int chess_get(METHOD *method);

    extern int chess_set(METHOD *method);

## 4.3.4 The Subtree_TBL.C Output Files

The <subtree>_TBL.C file contains the following three sections:

- An array of integers representing the OIDs for each MIB variable
- An array of OBJECT structures
- An initialized SUBTREE structure

The first section is an array of integers used as the OID of each MIB variable in the subtree, for example:

    static unsigned int elems[] = { ...

The next section is an array of OBJECT structures. There is one OBJECT for each MIB variable within the subtree.

An OBJECT represents a MIB variable and has the following fields:

- object_index --- The constant I_mib-variable from the subtree_TBL.H file.
- oid --- The variable's OID (points to a part of elems[]).
- type --- The variable's data type.
- getfunc --- The address of method routine to call for Gets.
- setfunc --- The address of method routine to call for Sets.

The master agent has no knowledge of object tables or MIB variables. It only maintains a registry of subtrees. When a request for a particular MIB variable arrives, it is processed as shown in the following example (where the MIB variable is mib_var and the subtree is subtree_1):

1. The master agent finds which subagent registered subtree_1 contains (for Get or Set routines or might contain (for GetNext routines mib_var).
2. The master agent sends an eSNMP message to the subagent who registered subtree_1):
3. The subagent consults its list of registered subtrees and locates subtree_1.
4. The subagent searches the object table of subtree_1 and locates the following:
   - mib_var (for Get and Set routines)
   - The first object lexicographically after mib_var (for Next or Bulk routines)
5. Then the appropriate method routine is called. If the method routine completes successfully, the data is returned to the master agent. If the method routine fails when doing a Get or Set, an error is returned. If the method routine fails when doing a GetNext, the code keeps trying subsequent objects in the object table of subtree_1 until either a method routine returns success or the table is exhausted. In either case, a response is returned.
6. If the master agent detects that subtree_1 could not return data on a Next routine, it recursively tries the subtree lexicographically after subtree_1.

   The last section is the SUBTREE structure itself. A pointer to this structure is passed to the eSNMP library routine esnmp_register to register the subtree. It is through this pointer that the library routines find the object structures. The following is an example of the chess subtree structure:

       SUBTREE chess_subtree = { "chess", "1.3.6.1.4.1.36.2.15.2.99",
                               { 11, &elems[0] }, objects, I_moveStatus};

   The SUBTREE structure has the following elements:

   - name --- The name of the subtree's base node.
   - dots --- The ASCII string representation of the subtree's OID. This is what actually gets registered.
   - oid --- The OID of the base node of the subtree. This points back to the array of integers.
   - object_tbl --- A pointer to the array of objects in the object table. It is indexed by the I_xxxx definitions found in the <subtree>_TBL.H file.
   - last --- The index of the last object in the object_tbl file. This is used to determine when the end of the table has been reached.

   # 4.4 Including the Routines and Building the Subagent

   After you finish defining the objects in your MIB and running the method routines through the MIB compiler to flush out the Set and Get routines, do the following to create the MIB subagent:

   1. Set up eSNMP handshake by running the main routine.
   2. Use the cc/include command to compile.
   3. Link the method routines with the library routines by running the following command:
      link<subtree>_TBL.C sys$lib:ucx$esnmp_shr.exe

   # Chapter 5
   Reviewing the Developer's Kit

   This chapter provides reference information about the routines in the eSNMP developer's kit. This chapter provides the following sections:

   - Interface Routines (Section 5.1)
   - Support Routines (Section 5.2)

   # 5.1 Interface Routines

   The interface routines are provided to developers writing the portion of the application programming interface (API) that handles the connection between the agent and the subagent. The interface routines include the following:

   - esnmp_init
   - esnmp_[un]register
   - esnmp_poll
   - esnmp_are_you_there
   - esnmp_trap
   - esnmp_term
   - esnmp_sysuptime

   # esnmp_init

   > Initializes the Extensible SNMP (eSNMP) subagent locally, and initiates communication with the master agent.

   ## Format

   > ### int esnmp_init (int *socket, char *sub-agent_identifier)

   ## ARGUMENTS

   > ### socket

   > The address of the integer that receives the socket descriptor used by eSNMP.

   > ### sub-agent_identifier

   > The address of a null-terminated string that uniquely identifies this subagent (usually a program name).

   ## DESCRIPTION

   > Call this routine during program initialization or to restart the eSNMP protocol. If you are restarting, the esnmp_init routine clears all registrations so each subtree must be registered again.

   > You should attempt to create a unique subagent identifier, perhaps using the program name argv[0] and additional descriptive text. The master agent does not open communications with a subagent whose subagent identifier is already in use.

   > This routine does not block waiting for a response from the master agent. After calling the esnmp_init routine, call the esnmp_register routine for each subtree that is to be handled by the subagent.

   ## Return Values

   > Status ESNMP_LIB_NO_CONNECTION | Could not initialize or communicate with the master agent. Try again after a delay.
   > ESNMP_LIB_OK | The esnmp_init routine has completed successfully.

   # esnmp_(un)register

   > Requests registration of a single MIB subtree.

   ## Format

   > ### int esnmp_register (subtree *subtree, int timeout, int priority *sub-agent_identifier)

   ## ARGUMENTS

   > ### subtree

   > A pointer to a subtree structure corresponding to the subtree to be handled. The code emitted by the MIB compiler files (xxx_tbl.c and xxx_tbl.h, where xxx is the subtree name) externally declare and initialize the subtree structures.

   > ### timeout

   > The number of seconds the master agent should wait for responses when requesting data in this subtree. This value must be between 0 and 10. If the value is 0, the default timeout is 3 seconds. Digital recommends you use the default.

   > ### priority

   > This is the registration priority. The entry with the largest number has the highest priority. The range is 0 to 65535. The subagent that registers a subtree with the highest priority over a range of object identifiers OIDs gets all requests for that range of OIDs.

   > Subtrees registered with the same priority are ranked in order by time of registration. The most recent registration has the highest priority.

   > The MIB-II subtrees registered by the os_mibs module provided with eSNMP software register at priority 1.

   ## DESCRIPTION

   > Before the master agent can pass eSNMP requests on to the subagent, it must register the willingness to process all messages for MIB variables subordinate to a subtree identifier.

   > Call the initialization routine esnmp_init prior to calling the esnmp_register. Call the esnmp_register function for each subtree structure corresponding to each subtree to be handled. At any time, subtrees can be unregistered by calling esnmp_unregister and then be reregistered by calling the esnmp_register.

   > When restarting the eSNMP protocol by calling esnmp_init, all registrations are cleared. All subtrees must be reregistered.

   > A subtree is identified by the base MIB name and its corresponding OID number of the node that is the parent of all MIB variables contained in the subtree. For example: The MIB-II tcp subtree has an OID of 1.3.6.1.2.1.6. All elements subordinate to this have the same first seven digits and are included in the subtree's object table. The subtree can also be a single MIB object (a leaf node) or even a specific instance.

   > By registering a subtree, the subagent indicates that it will process eSNMP requests for all MIB variables (or OIDs) within that subtree's range. Therefore, a subagent should register the most fully qualified (longest) subtree that still contains its instrumented MIB variables.

   > The master agent does not permit a subagent to register the same subtree more than once. However, subagents may register subtrees with ranges that overlap the OID ranges of subtrees previously registered and subagents may also register subtrees registered by other subagents.

   > For example, TCP/IP for OpenVMS supports MIB-II. In the eSNMP environment, the product ships a subagent that does not register MIB-II (1.3.6.1.2.1). Instead eSNMP registers the following MIBs: system, interfaces, at, ip, icmp, tcp, udp, and snmp.

   > In addition to these MIBs, TCP/IP for OpenVMS also registers the Host Resource MIB.

   > All of these MIBs are registered at priority 1. Any subagent that registers at a higher priority (greater than 1), will override these registrations.

   ## Return Values

   > > Note

   > > This status indicates only the initiation of the request. The actual status returned in the master agent's response is returned in a subsequent call to the esnmp_poll routine.

   > ESNMP_LIB_OK | The esnmp_register routine has completed successfully.
   > ESNMP_LIB_BAD_REG | The esnmp_init routine has not been called, the timeout parameter is invalid, or the subtree has already been queued for registration.
   > ESNMP_LIB_LOST_CONNECTION | The subagent has lost communications with the master agent.

   ## Example

   >     #include <esnmp.h>
   >     #define RESPONSE_TIMEOUT     0    /* use the default time set
   >                                          in OPEN message */
   >     #define REGISTRATION_PRIORITY 10  /* priority at which subtrees
   >                                          will register */

   >     extern SUBTREE ipRouteEntry_subtree;

   >     status = esnmp_register( &ipRouteEntry_subtree,
   >                              RESPONSE_TIMEOUT,
   >                              REGISTRATION_PRIORITY );
   >     if (status != ESNMP_LIB_OK) {"
   >         printf ("Could not queue the 'ipRouteEntry' \\n");
   >         printf ("subtree for registration\\n");
   >     }

   # esnmp_poll

   > Processes a pending message that sent by the master agent.

   ## Format

   > ### int esnmp_poll ()

   ## DESCRIPTION

   > This routine is called after the select() call has indicated data is ready on the eSNMP socket. (This socket was returned from the call to the esnmp_init routine.

   > If a received message indicates a problem, an entry is made to the syslog file and an error status is returned.

   > If the received message is a request for eSNMP data, the object table is checked and the appropriate method routines are called.

   ## Return Values

   > ESNMP_LIB_OK | The esnmp_poll routine completed successfully.
   > ESNMP_LIB_BAD_REG | The master agent failed in a previous registration attempt. See the log file.
   > ESNMP_LIB_DUPLICATE | An OPEN error occurred. A duplicate subagent identifier has already been received by the master agent.
   > ESNMP_LIB_NO_CONNECTION | The master agents OPEN request failed. Restart the connection after a delay. See the log file.
   > ESNMP_LIB_CLOSE | A CLOSE message was received. Restart the connection after a delay.
   > ESNMP_LIB_NOTOK | An eSNMP protocol error occurred and the packet was discarded.
   > ESNMP_LIB_LOST_CONNECTION | Communication with the master agent was lost. Restart the connection.

   # esnmp_are_you_there

   > Sends ICMP ECHO_REQUEST packets (ping) to the master agent.

   ## Format

   > ### int esnmp__are_you_there ()

   ## DESCRIPTION

   > The esnmp_are_you_there routine does not block waiting for a response. It is intended to cause the master agent to reply immediately. The response should be processed by calling the esnmp_poll routine.

   > If no response is received within the timeout period, the application code restarts the eSNMP protocol by calling the esnmp_init routine. There are no timers maintained by the eSNMP library.

   ## Return Values

   > ESNMP_LIB_OK | The ICMP ECHO_REQUEST was sent.
   > ESNMP_LIB_LOST_CONNECTION | The ICMP ECHO_REQUEST packet cannot be sent because the master agent is down.

   # esnmp_trap

   > Sends a trap message to the master agent.

   ## Format

   > ### int esnmp_trap (int *generic_trap, int specific_trap, char *enterprise, varbind *vb)

   ## ARGUMENTS

   > ### generic_trap

   > A generic trap code.

   > ### specific_trap

   > A specific trap code.

   > ### enterprise

   > An enterprise OID string in dot notation.

   > ### vb

   > A VARBIND list of data (a null pointer indicates no data).

   ## DESCRIPTION

   > This function can be called any time. If eSNMP has not initialized through the master agent, traps are queued and sent when communication is possible.

   > The trap message is actually sent to the master agent after it responds to the esnmp_init routine. This occurs with every API call and for most esnmp_register routines. The quickest process to send traps to the master agent is to call the esnmp_init, esnmp_poll, and esnmp_trap routines.

   > The master agent formats the trap into an eSNMP trap message and sends it to management stations based on its current configuration.

   > The master agent does not respond to the content of the trap. However, the master agent does return a value that indicates whether the trap was received successfully.

   ## Return Values

   > ESNMP_LIB_OK | The routine has completed successfully.
   > ESNMP_LIB_LOST_CONNECTION | Could not send the trap message to master agent.
   > ESNMP_LIB_NOTOK | Something failed and the message could not be generated.

   # esnmp_term

   > Sends a close message to the master agent and shuts down eSNMP.

   ## Format

   > ### void esnmp_term (void)

   ## DESCRIPTION

   > Subagents should call this routine when terminating, so that the master agent can update its MIB registry more quickly.

   ## Return Values

   > ESNMP_LIB_OK | The esnmp_term always returns ESNMP_LIB_OK even if the packet could not be sent.

   # esnmp_sysuptime

   > Converts UNIX system time obtained from gettimeofday into a value with the same time base as sysUpTime.

   ## Format

   > ### unsigned int esnmp_sysuptime (struct timeval *timestamp)

   ## ARGUMENT

   > ### *timestamp

   > A pointer to struct timeval contains a value obtained from the gettimeofday system call. The structure is defined in include/sys/time.h.

   > Previous | Next | Contents