Solaris System Management Agent Developer's Guide

demo_module_7 Code Example for Dynamic Updates of Multiple Instance Modules

The demo_module_7 code example shows how to implement multiple instance modules. The demo is by default located in the directory /usr/demo/sma_snmp/demo_module_7. The README_demo_module_7 file in that directory contains instructions that describe how to perform the following tasks:

Modifying the demo_module_7 Code

The following procedure lists the steps you should follow to enable your module to be dynamically updated. The procedure uses examples from the demo_module_7.c code to illustrate each step. The code contains modifications to code templates that were produced by using mib2c on a MIB group in SDK-DEMO1–MIB.txt.

The demo_module_7 example registers new instances as contexts that represent files. Subsequent snmpget requests to these contexts retrieve the size of a specified file.

ProcedureHow to Enable Dynamic Update of a Multi-Instance Module

  1. Define two objects in the MIB for the module:

    • A string with read-write MAX-ACCESS that, when set, registers the specified string as a context name.

    • A string with read-write MAX-ACCESS that, when set, unregisters the specified string context name.

    For example, the following objects, which are defined in the SDK-DEMO1-MIB.txt file, register and unregister a context string that is set with an snmpset request:

     me1createContext OBJECT-TYPE
        SYNTAX      OCTET STRING (SIZE(0..1024))
        MAX-ACCESS  read-write
        STATUS      current
        DESCRIPTION
                    "String which when set, registers a context."
        ::= { me1MultiGroup 2 }
        
      me1removeContext OBJECT-TYPE
        SYNTAX      OCTET STRING (SIZE(0..1024))
        MAX-ACCESS  read-write
        STATUS      current
        DESCRIPTION
                    "String which when set, unregisters a context."
        ::= { me1MultiGroup 3 }
  2. In the module, declare the location within the MIB tree where the OIDs for the context objects should be registered.

    For example, the following code declares the OIDs for context strings:

    // Registers a context
       static oid me1createContext_oid[] =
      { 1,3,6,1,4,1,42,2,2,4,4,6,1,2,0 }; 
    
       // Unregisters a context
       static oid me1removeContext_oid[] =
      { 1,3,6,1,4,1,42,2,2,4,4,6,1,3,0 };
  3. In the module, register both OIDs of the context objects with the SMA.

    The following code shows an example:

        // Create a read-write registration handler named filesize, 
        // which calls the set_createContext function to service snmp requests
        // for the me1createContext_oid object.  The OID_LENGTH argument
        // calculates the length of the me1createContext_oid.
        myreg1 = netsnmp_create_handler_registration
                                           ("filesize",
             set_createContext,
             me1createContext_oid,
             OID_LENGTH(me1createContext_oid),
             HANDLER_CAN_RWRITE);
             
         
        // Create a read-write registration handler named filesize, 
        // which calls the set_removeContext function to service snmp requests
        // for the me1removeContext_oid object.  The OID_LENGTH argument
        // calculates the length of the me1removeContext_oid.
        myreg1 = netsnmp_create_handler_registration
            ("filesize",
              set_removeContext,
              me1removeContext_oid,
              OID_LENGTH(me1removeContext_oid),
              HANDLER_CAN_RWRITE);
  4. In the set_createContext() function handler code, extract the context name string from the SNMP message. Register the string as a new context.

    The following code shows an example:

    int
    set_createContext(netsnmp_mib_handler *handler,
          netsnmp_handler_registration *reginfo,
          netsnmp_agent_request_info *reqinfo,
          netsnmp_request_info *requests)
    {
    
    // This handler handles set requests on the m1createContext_oid.
    // The handler extracts the string from the snmp set request and
    // uses it to register a new context for the me1filesize_oid.
    //
    // For detailed info. on net-snmp set processing, 
    // see http://www.net-snmp.org/tutorial-5/toolkit/mib_module/index.html 
    // The agent calls each SNMP mode in sequence. We include a case
    // statement with only a break statement for each snmp set mode the
    // the agent handles.  In this example, we implement only the
    // snmp set action mode.  The case statement 
    // transfers control to the default: case when no other condition 
    // is satisfied. 
    netsnmp_handler_registration *myreg;
    char *context_names[256];
    
    switch(reqinfo->mode) {
    
    case MODE_SET_RESERVE1:
                break;
    case MODE_SET_RESERVE2:
                break;
    case MODE_SET_FREE:
                break;
    case MODE_SET_ACTION:
    
        // You must allocate memory for this variable because
        // the unregister_mib function frees it.
        filename = malloc(requests->requestvb->val_len + 1);
        snprintf(filename, sizeof(filename), "%s",  (u_char *)
                    requests->requestvb->val.string);
                    
        // Create a registration handler for the me1filesize_oid 
        // object in the new context name specified by 
        // the snmp set on the me1createContext OID. 
        myreg = netsnmp_create_handler_registration 
    	         ("test",
                 get_test,
                 me1filesize_oid,
                 OID_LENGTH(me1filesize_oid),
                 HANDLER_CAN_RONLY);
        myreg->contextName=filename;
        break;
    case MODE_SET_COMMIT:
                break;
    case MODE_SET_UNDO:
                break;
    
    default:
        /* we should never get here, so this is a really bad error */
        DEBUGMSGTL(("filesize", "default CALLED\n"));
    }
        return SNMP_ERR_NOERROR;
    }
  5. In the set_removeContext handler code, extract the context name string from the SNMP message. Unregister the context.

    The following code shows an example:

    // This handler handles set requests on the m1removeContext_oid     
    int
    set_removeContext(netsnmp_mib_handler *handler,
          netsnmp_handler_registration *reginfo,
          netsnmp_agent_request_info *reqinfo,
          netsnmp_request_info *requests)
    {
    
        static int PRIORITY = 0;
        static int SUB_ID = 0;
        static int RANGE_UBOUND = 0;
    
        switch(reqinfo->mode) {
    
            case MODE_SET_RESERVE1:
                break;
            case MODE_SET_RESERVE2:
                break;
            case MODE_SET_ACTION:
    
           snprintf(filename, sizeof(filename), "%s\n",  (u_char *)
                 requests->requestvb->val.string);
      unregister_mib_context(me1filesize_oid, OID_LENGTH(me1filesize_oid), 
           PRIORITY, SUB_ID, RANGE_UBOUND,
           filename);
           break;
    
               case MODE_SET_COMMIT:
                   break;
               case MODE_SET_FREE:
                   break;
               case MODE_SET_UNDO:
                   break;
    
        default:
            /* we should never get here, so this is a really bad error */
            DEBUGMSGTL(("filesize", "set_removeContext CALLED\n"));
        }
      return SNMP_ERR_NOERROR;
    }
  6. In the handler code for a new context, get the context string from the reginfo->contextName variable.

     /* This handler is called to handle snmp get requests for 
           the me1filesize_oid for a specified context name. */
       
    int
    get_test(netsnmp_mib_handler *handler,
          netsnmp_handler_registration *reginfo,
          netsnmp_agent_request_info *reqinfo,
          netsnmp_request_info *requests)
    {
    
    /* We are never called for a GETNEXT if it's registered as an
       "instance", as it's "magically" handled for us.  */
    
    /* An instance handler also only hands us one request at a time, so
       we don't need to loop over a list of requests; we'll only get one. */
    
    struct stat buf;
    static int fd = 0;
    
    switch(reqinfo->mode) {
    
    case MODE_GET:
    
       if (strcmp(reginfo->contextName, filename) == 0) 
    
         // An open() for reading only returns without delay.
         if ((fd = open(filename, O_NONBLOCK | O_RDONLY)) == -1)
            DEBUGMSGTL(("filesize", "ERROR\n")); 
    
         if (fstat(fd, &buf) == -1)
           DEBUGMSGTL(("filesize", "ERROR\n")); 
         else
           DEBUGMSGTL(("filesize", "FILE SIZE IN BYTES = %d:\n", buf.st_size));
           
         snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, 
         (u_char *) &buf.st_size /* XXX: a pointer to the scalar's data */, 
         sizeof(buf.st_size) /* XXX: the length of the data in bytes */);
    
            break;
    
       default:
        /* we should never get here, so this is a really bad error */
           return SNMP_ERR_GENERR;
    }
    
    return SNMP_ERR_NOERROR;
    }

Registering New Instances in the Module

The demo_module_7 code example module registers context name strings that represent files. GET requests to these contexts retrieve the size of the file.

You do not need to edit the module to register new instances. The module can be dynamically updated to register new instances through the snmpset command. A management application passes the file name to the module by issuing an snmpset command, of the following format:


/usr/sfw/bin/snmpset -v 3 -u username -l authNoPriv -A "password" \
 hostname createContext_OID s "filename"

For example, the register_file script in the demo_module_7 directory issues a command that registers the file /usr/sfw sbin/snmpd as a new context name with the module:


/usr/sfw/bin/snmpset -v 3 -u myuser -l authNoPriv \
-A "mypassword" localhost .1.3.6.1.4.1.42.2.2.4.4.6.1.2.0 \
s "/usr/sfw/sbin/snmpd"

The module registers the set_createContext handler to handle incoming snmpset requests for the specified OID. The set_createContext handler registers the new file name as a context string in the contextName member of the netsnmp_registration_handler struct for the me1filesize_oid.

A management application can request the size of the file in blocks by issuing an snmpget command of the following format:


/usr/sfw/bin/snmpget -v 3 -u username -n contextname\
 -l authNoPriv -A "password" hostname me1filesize_oid

For example, the get_filesize script in the demo_module_7 directory issues a command that is similar to the following command:


/usr/sfw/bin/snmpget -m+SDK-DEMO6-MIB -v 3 -u myuser \
-n "/usr/sfw/sbin/snmpd" -l authNoPriv -A "mypassword" localhost \
.1.3.6.1.4.1.42.2.2.4.4.6.1.1.0