Solaris System Management Agent Developer's Guide

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;
    }