array-user Frequently Asked Questions Page


[Official FAQ] | [Container indexes vs MIB Indexesa] | [Row Creation]

This is just a quick page to answer some common questions that aren't covered in the official FAQ. There is also a tutorial document from the OpenHPI project that covers a simple array-user sub-agent. It can be found here.

Container indexes vs MIB indexes

The array-user code uses containers, which are a generic data interface, similar to a database. Like a database, you use an index (aka key) to access and sort the data. Containers use a compare function provided by the user to determine the sort order. The function is called with a pointer to two data itmes, and must return a value indicating which of the two has the lesser index value. So, by providing a second compare function allows the user to access the data in a different order.

SNMP tables have indexes. A table index may have multiple components which, taken together, uniquely identify a row.

Now, when the two are used together, it easy to get confused. All of the MIB indexes, taken together, are the primary container index. Even if a MIB table has a dozen indexes, the container only has one.

Dave Shield put it this way:

The (primary) container index is effectively equivalent to the sequence of OID
instance subidentifiers, i.e. everything following the object OID itself.

So using the Host Resources hrPartitionTable as an example, and
taking the two index values
           hrDeviceIndex    = 99
           hrPartitionIndex = 42

then this instance of hrPartitionLabel would have the OID
	.1.3.6.1.2.1.25.3.7.1.2.99.42

where ".1.3.6.1.2.1.25.3.7.1.2" is the OID of the hrPartitionLabel
object, and "99.42" are the instance subidentifiers.

The primary container index would then also be "99.42"

An example

To clarify futher, here's an example. Let's say we are creating a SNMP interface to a hotel reservation system. The (simplified) table looks like this:

guestTable
  guestEntry INDEX { building, room }
    building INTEGER
    room     INTEGER
    name     STRING

So, the MIB has two indexes, the building and room numbers. The primary MIB index is the building, and the secondary MIB index is the room. However, the primary index ofr the container will be the combined index OID (building.room). The default compare routine for containers assumes that the data record's first component is a netsnmp_index (and the array-user code generates a structure that starts with a netsnmp_index), so you don't need to provide a comparison routine. If you wanted to provide your own compare routine, it might look something like this:

  int
  netsnmp_compare_netsnmp_index(guestTable *lh_guest, guestTable *rh_guests)
  {
    /* compare building, then room */
    if(lh_guest->building == rh_guest->building) {
        if(lh_guest->room == rh_guest->room)
           return 0;
        else {
           if(lh_guest->room < rh_guest->room)
              return -1;
           else
              return 1;
        }
    }
    else {
       if(lh_guest->building < rh_guest->building)
	 return -1;
       else
         return 1;
    }
  }

Remember, for the array-user, as provided, the data for a table is internal to the agent. So we now have a container with the guest data, and we can look up data by building and room number. What if our application now needs to generate a guest report, but sorted by name? We have the data, but in the wrong sort order. This is where you would use a secondary index to the container. The new compare might look like this:

  int
  netsnmp_compare_netsnmp_index(guestTable *lh_guest, guestTable *rh_guests)
  {
     /* compare name, then building and room */
     int rc = strcmp(lh_guest->name,rh_guest->name);
     if(rc != 0)
        return rc;

     if(lh_guest->building == rh_guest->building) {
        if(lh_guest->room == rh_guest->room)
             return 0;
        else {
           if(lh_guest->room < rh_guest->room)
              return -1;
           else
              return 1;
        }
     }
     else {
        if(lh_guest->building < rh_guest->building)
           return -1;
        else
           return 1;
     }
  }

Creating new rows

Integer IndexString Index
    xxTable_context *context;
    netsnmp_index   index;
    oid             tmp_oid[MAXLEN];

    /* set temp oid for new row */
    tmp_oid[ 0 ] = 42; 

    /* set temp index */
    index.oids = tmp_oid;
    index.len = 1

    /* create row */
    context = xxTable_create_row(&index);

    /* fill in data */
    context->abc = some_value;

    /* insert row in container */
    CONTAINER_INSERT(cb.container, context);
    xxTable_context *context;
    netsnmp_index   index;
    oid             tmp_oid[MAXLEN];

    /* set temp oid for new row with string index 'hi' */
    tmp_oid[ 0 ] = 2;  /* length *
    tmp_oid[ 1 ] = 'h'; 
    tmp_oid[ 2 ] = 'i'; 

    /* set temp index */
    index.oids = tmp_oid;
    index.len = 3;

    /* create row */
    context = xxTable_create_row(&index);

    /* fill in data */
    context->abc = "bob";

    /* insert row in container */
    CONTAINER_INSERT(cb.container, context);



Page Last modified: Wed Mar 12 13:49:32 PST 2003
[an error occurred while processing this directive]