Subject: snmpconf PM Issue #8, createRow() function

From: Steve Waldbusser <[email-masked]>
Date: Mon, 16 Jul 2001 23:35:52 -0700

One of the action items is to potentially expand the helper function
in the API to support createAndGo row creation operations.

BACKGROUND (review of Minneapolis discussion)

Currently we have setRowStatus which performs a createAndWait:
    integer setRowStatus(string oid, integer maxTries
                         [, integer freeOnException , integer seed,
                         string context, NonLocalArgs])

This works essentially as follows:

 var index, pdu;
 p = newPDU();

 // setRowStatus finds an empty row and creates it
 index = setRowStatus("hlHostControlStatus.*", 20, ...);
 if (index == -1)
     return; /* couldn't find a free row */
 writeVar(p, 0, "hlHostCtlDataSource." + index,
          "ifIndex." + ev(0), Oid);
 writeVar(p, 1, "hlHostCtlNlMaxDesiredEntries." + index, 100, Integer);
 writeVar(p, 2, "hlHostCtlAlMaxDesiredEntries." + index, 100, Integer);
 writeVar(p, 3, "hlHostCtlOwner." + index, "policy", String);
 writeVar(p, 4, "hlHostCtlStatus." + index, 1, Integer);
 snmpsend(p, 5, OP_SET);

Note the '*' in the oid argument to setRowStatus. It is repeatedly
replaced with random index values until one succeeds.

In order to accomplish createAndGo, this substitution would need to
happen in all columns at once. Use of this function would take this
form:

 var index, p = newPDU();
 
 writeVar(p, 0, "hlHostCtlDataSource.*", "ifIndex." + ev(0), Oid);
 writeVar(p, 1, "hlHostCtlNlMaxDesiredEntries.*", 100, Integer); 
 writeVar(p, 2, "hlHostCtlAlMaxDesiredEntries.*", 100, Integer);
 writeVar(p, 3, "hlHostCtlOwner.*", "policy", String);
 writeVar(p, 4, "hlHostCtlStatus.*", 1, Integer); 
 createRow(p, ...);

Such a function could also abstract out which mechanism was supported
by the agent because it can fall back to the other one on failure.

NEW ACCESSOR FUNCTION

With all the details worked out the new accessor function is as follows:

    integer createRow(integer pdu, integer numVarbinds,
                      integer statusColumn, integer maxTries,
                      integer indexRange, integer &index
                      [, integer freeOnException, string context,
                      NonLocalArgs]) 

        createRow is used to automate the process of creating a row in
        a read-create table. In particular, it encapsulates the
        algorithm behind using either the createAndWait or createAndGo
        mechanism and the algorithm for finding an unused row in the
        table.

        'pdu' is the handle to a PDU allocated by newPDU(). Note that
        no actual SNMP PDU needs to be generated and parsed when the
        policy MIB agent resides on the same system as the managed
        elements.

        'numVarbinds' is a integer greater than zero that specified
        which varbinds in the PDU will be used in this
        operation. The first 'numVarbinds' in the PDU are used.
        Each such varbind must be of a special form in which the
        object name must have one of its subids replaced with a '*'
        character (e.g. "1.3.6.1.3.1.99.1.2.1.9.*"). The '*' must
        replace any integer index item that may be set to some random
        value.

        'statusColumn' identifies which varbind in 'pdu' should be
        treated as the RowStatus column, where 0 identifies the 1st
        varbind.

        createRow will come up with a random integer index value
        and will substitute that value in place of the '*' subid in
        each varbind. It will then set the value of the RowStatus
        column to select the 'createAndGo' mechanism and execute the
        set. If the attempt fails due to unavailability of the
        'createAndGo' mechanism, it will retry with the
        'createAndWait' mechanism selected. If the attempt fails due
        to the chosen index value already in use, the operation will
        be retried with a different random index value. It will
        continue to retry different index values until it succeeds,
        until it has made 'maxTries' attempts, or until it encounters
        an error.

        All random index values must be less than 'indexRange'. This
        is so that values are not attempted for an index that fall
        outside of that index's restricted range (e.g. 0..65535).

        If the optional 'freeOnException' argument is present and
        equal to 1, the agent will free this row by setting RowStatus
        to 'destroy' if later in the same script invocation this
        script dies with a run-time exception or by a call to die().
        Note that this does not apply to subsequent invocations of
        the script.

        The optional 'context' argument contains the context to
        operate on. If this argument is not present, the context of
        "this element" will be used. If this argument is the zero
        length string, the default context is used.

        The optional 'NonLocalArgs' provide addressing and security
        information to perform an SNMP operation on a different system
        than "this element".

        The results of the operation will be placed in the same
        PDU. If an SNMP error occurred, the PDU will remain
        unmodified except for the following:

          1) If the response PDU had a nonzero error-index, the
             varbind specified by the error-index will have its type
             field replaced with associated error-status constant.
          2) If the response PDU contained varbinds with exceptions,
             the type field of those varbinds will be replaced with
             the appropriate exception (Nosuchobject,
             NosuchInstance, or Endofmibview).
          3) If the error-status was zero and there were no
             exceptions, the PDU will remain unmodified. (some
             examples of situations where this will apply are timeout
             and authentication failure).
             
        createRow returns the proper SNMP Error Constant if
        an SNMP error occurs, otherwise it returns zero. If no SNMP
        error occurs but the operation does not succeed due to the
        following reasons, 'index' will be set to -1:
            1) Unsuccessful after 'maxTries'
            2) An object name had no '*' in it
            3) An object name had more than one '*' in it

        If successful, 'index' will be set to the successful integer
        index.

For example:

 var index, p = newPDU();
 
 writeVar(p, 0, "hlHostCtlDataSource.*", "ifIndex." + ev(0), Oid);
 writeVar(p, 1, "hlHostCtlNlMaxDesiredEntries.*", 100, Integer); 
 writeVar(p, 2, "hlHostCtlAlMaxDesiredEntries.*", 100, Integer);
 writeVar(p, 3, "hlHostCtlOwner.*", "policy", String);
 writeVar(p, 4, "hlHostCtlStatus.*", 1, Integer); 
 if (createRow(pdu, 5, 4, 20, 65535, index) == 0 || index == -1)
   return; 
 // index now contains index of new row

Any comments?

An open question is whether or not to keep the setRowStatus function as
well. createRow doesn't allow some createAndWait functionality such as
inspecting the agent's default values before setting the row to active.
(setRowStatus is the simpler of the two functions).

Steve