Search code examples
clinuxnet-snmp

How do I use netsnmp_query_walk() or netsnmp_query_get()?


I've successfully used the following to read some simple SNMP values from a local snmpd:

snmp_open( &session )
snmp_pdu_create( SNMP_MSG_GET );
snmp_add_null_var( pdu, oid, len ); // multiple lines like this
snmp_sync_response( ss, pdu, &response );
for ( netsnmp_variable_list *vars = response->variables; vars; vars = vars->next_variable )
{
    // look at vars->name, vars->name_length, and vars->val.integer
}

While this works for a few simple integer scalars, I also have some tables I need to read. I've tried both the OID of the table and the oid of the table entry in snmp_add_null_var(), but snmp_sync_response() returns with an error code indicating that OID cannot be found.

So browsing the header files I came across these calls. I suspect one of these is likely to be what I want to be using:

  1. netsnmp_query_walk()
  2. netsnmp_query_get()

However, I cannot figure out how to use them. This is what I've tried:

netsnmp_variable_list *vb = (netsnmp_variable_list*)SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
if ( vb == NULL ) ...
snmp_set_var_objid( vb, oid, len );
int rc = netsnmp_query_walk( vb, ss );
//int rc = netsnmp_query_get( vb, ss );

...but at this point, rc is always == -1 which I'm guessing means there was an error. How do I use these, or, is there a better API I should be using?


Solution

  • I suspect there were several problems. The first is this line:

    snmp_pdu_create( SNMP_MSG_GET );
    

    Instead of calling MSG_GET, it would probably have helped if I'd looked into using SNMP_MSG_GETBULK. But it turns out the SNMP server against which I'm connecting only supports SNMPv1, and GETBULK is specific to SNMPv2+, so I didn't bother digging.

    What I found instead is how to use GETNEXT, which can be used to traverse the table one variable at a time. Here is how the code works:

    oid = ....; // start with a known OID, like the table you want to read
    while ( true )
    {
        pdu = snmp_pdu_create( SNMP_MSG_GETNEXT );
        snmp_add_null_var( pdu, oid, len );
        status = snmp_synch_response( ss, pdu, reply );
        if ( status != STAT_SUCCESS )
        {
            // either an error, or there is nothing left to read
            snmp_free_pdu( reply );
            break;
        }
        for ( netsnmp_variable_list *vars=reply->variables; vars; vars=vars->next_variable )
        {
            // make sure you remember this OID so you know what to use
            // when you get back to the top of the while() loop
            oid = ...vars->name[], vars->name_length...;
    
            // do something with this snmp value, such as:
            std::cout << oid << ": " << *vars->val.integer << std::endl;
        }
        snmp_free_pdu( reply );
    }