Stéphane Stéphane - 5 months ago 32x
Linux Question

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?


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